Рассмотрим вектор символов, pool
, элементы которого (с нулевым заполнением) двоичные числа с цифрами max_len
.
max_len <- 4
pool <- unlist(lapply(seq_len(max_len), function(x)
do.call(paste0, expand.grid(rep(list(c('0', '1')), x)))))
pool
## [1] "0" "1" "00" "10" "01" "11" "000" "100" "010" "110"
## [11] "001" "101" "011" "111" "0000" "1000" "0100" "1100" "0010" "1010"
## [21] "0110" "1110" "0001" "1001" "0101" "1101" "0011" "1011" "0111" "1111"
Я хотел бы попробовать n
этих элементов с ограничением, что ни один из выбранных элементов не является префиксами любого из другие элементы сэмплирования (т.е. если мы проецируем 1101
, мы запрещаем 1
, 11
и 110
, тогда как если мы опробуем 1
, мы запретим те элементы, начинающиеся с 1
, такие как 10
, 11
, 100
и т.д.).
Ниже приведена моя попытка использовать while
, но, конечно, это медленно, когда n
велико (или когда он приближается к 2^max_len
).
set.seed(1)
n <- 10
chosen <- sample(pool, n)
while(any(rowSums(outer(paste0('^', chosen), chosen, Vectorize(grepl))) > 1)) {
prefixes <- rowSums(outer(paste0('^', chosen), chosen, Vectorize(grepl))) > 1
pool <- pool[rowSums(Vectorize(grepl, 'pattern')(
paste0('^', chosen[!prefixes]), pool)) == 0]
chosen <- c(chosen[!prefixes], sample(pool, sum(prefixes)))
}
chosen
## [1] "0100" "0101" "0001" "0011" "1000" "111" "0000" "0110" "1100" "0111"
Это можно немного улучшить, изначально удалив из pool
те элементы, включение которых означает, что в pool
осталось меньше элементов, чтобы взять общий образец размера n
. Например, когда max_len = 4
и n > 9
мы можем сразу удалить 0
и 1
из pool
, так как, включив либо, максимальный образец будет равен 9 (либо 0
, и восемь 4-символьных элементов начиная с 1
или 1
и восьми 4-символьных элементов, начинающихся с 0
).
На основе этой логики мы могли бы затем опустить элементы из pool
, прежде чем брать исходный образец, с чем-то вроде:
pool <- pool[
nchar(pool) > tail(which(n > (2^max_len - rev(2^(0:max_len))[-1] + 1)), 1)]
Может ли кто-нибудь подумать о лучшем подходе? Я чувствую, что я пропускаю нечто гораздо более простое.
ИЗМЕНИТЬ
Чтобы прояснить мои намерения, я опишу пул как набор ветвей, где узлы и концы являются узлами (элементами pool
). Предположим, что желтый node на следующем рисунке (т.е. 010) был нарисован. Теперь вся красная "ветвь", состоящая из узлов 0, 01 и 010, удаляется из пула. Это то, что я имел в виду, запрещая выборку узлов, которые "префиксные" узлы уже находятся в нашем примере (а также те, которые уже предваряются узлами в нашем примере).
Если выборка node была на полпути вдоль ветки, например, 01 на следующем рисунке, то все красные узлы (0, 01, 010 и 011) запрещены, так как префиксы 0 и 01 префиксов и 010, и 011.
Я не хочу пробовать ни 1 или 0 на каждом соединении (т.е. ходить вдоль ветвей, переворачивающих монеты на вилках) - это хорошо, чтобы иметь как в образце, так и: (1) родители (или грандиозные, родители и т.д.), или дети (внуки и т.д.) из node уже не отбираются; и (2) при выборке node останутся достаточные узлы для достижения желаемого образца размером n
.
На втором рисунке выше, если 010 был первым выбором, все узлы в черных узлах все еще (в настоящее время) действительны, предполагая n <= 4
. Например, если n==4
и мы выбрали node 1 next (и поэтому наши выборки теперь включали 01 и 1), мы впоследствии запретили бы node 00 (из-за правила 2 выше), но все же могли бы выбрать 000 и 001, давая нам наш 4-элементный образец. Если n==5
, с другой стороны, node 1 будет отменено на этом этапе.