Здесь у меня есть целые числа 1:7
для четырех различных разделов, т.е. {1}, {2,3,4}, {5,6} и {7} и эти разделы написаны в списке, то есть list(1,c(2,3,4),c(5,6),7)
. Я рассматриваю разделы как наборы, так что различные перестановки элементов в одном разделе должны распознаваться как один и тот же. Например, list(1,c(2,3,4),c(5,6),7)
и list(7,1,c(2,3,4),c(6,5))
эквивалентны.
Обратите внимание, что нет повторения для элементов в списке, например, нет list(c(1,2),c(2,1),c(1,2))
, так как эта проблема обсуждает исключительные разделы по всему набору.
Я перечислил некоторые из различных перестановок в списке, lst
как показано ниже
lst <- list(list(1,c(2,3,4),c(5,6),7),
list(c(2,3,4),1,7,c(5,6)),
list(1,c(2,3,4),7,c(6,5)),
list(7,1,c(3,2,4),c(5,6)))
и я хочу убедиться, что все перестановки эквивалентны. Если да, то мы получим результат TRUE
.
То , что я сделал до сих пор является для сортировки элементов в пределах каждого раздела, и используются setdiff()
с interset()
и union()
судить о нем (см моего кода ниже)
s <- Map(function(v) Map(sort,v),lst)
equivalent <- length(setdiff(Reduce(union,s),Reduce(intersect,s),))==0
Тем не менее, я думаю, что этот метод будет медленным, когда размер раздела увеличивается. Есть ли более быстрый подход, чтобы сделать это? Ценим заранее!
- некоторые тестовые случаи (данные небольшого размера)
# should return `TRUE`
lst1 <- list(list(1,c(2,3,4),c(5,6)),
list(c(2,3,4),1,c(5,6)),
list(1,c(2,3,4),c(6,5)))
# should return `TRUE`
lst2 <- list(list(1:2, 3:4), list(3:4, 1:2))
# should return `FALSE`
lst3 <- list(list(1,c(2,3,4),c(5,6)), list(c(2,3,4),1,c(5,6)), list(1,c(2,3,5),c(6,4)))
источник
Map
звонковlst_equal = list(list(1:2, 3:4), list(3:4, 1:2))
а также тот, где должен быть результатFALSE
, может бытьlst_false <- list(list(1,c(2,3,4),c(5,6)), list(c(2,3,4),1,c(5,6)), list(1,c(2,3,5),c(6,4)))
FALSE
. Таким образом, когда ответ работает на некоторых, но не на всех тестовых случаях, легко определить причину. Когда есть только один пример, вы теряете нюанс в результатах теста. Также приятно добавлять новые примеры, а не изменять существующие примеры под людьми, которые уже работали над ними.lst
потенциально велика , вы могли бы повысить эффективность с другими подходами. Например, первая проверка,length(unique(lengths(lst))) == 1
которая очень быстро вернуласьFALSE
бы, если бы у любого из внутренних списков было неправильное число элементов ....lst
, по сравнениюlst[[i]]
сlst[[1]]
, и таким образом вы можете остановиться , как только вы нашли несоответствие, а не делать все сравнения. Еслиlst
это long иFALSE
s распространены, это может привести к значительному увеличению эффективности, но, вероятно, не стоит этого.Ответы:
Пост про
R
и любой вариант поста не будет полным без решения с использованием rcpp .Для максимальной эффективности выбор правильной структуры данных будет иметь первостепенное значение. Наша структура данных должна хранить уникальные значения, а также иметь быструю вставку / доступ. Это именно то, что воплощает std :: unordered_set . Нам нужно только определить, как мы можем однозначно идентифицировать каждого
vector
из неупорядоченныхintegers
.Введите основную теорему арифметики
Соглашение о свободной торговле утверждает, что каждое число может быть однозначно представлено (с точностью до порядка факторов) произведением простых чисел.
Вот пример, демонстрирующий, как мы можем использовать FTA, чтобы быстро расшифровать, если два вектора эквивалентны с точностью до порядка (NB
P
ниже - список чисел простых чисел ...)(2, 3, 5, 7, 11, etc.)
:Из этого мы видим, что
vec1
иvec3
правильно отображаются на одно и то же число, аvec2
сопоставляются с другим значением.Поскольку наши действительные векторы могут содержать до ста целых чисел меньше 1000, применение FTA приведет к чрезвычайно большим числам. Мы можем обойти это, используя преимущество логарифма:
Имея это в нашем распоряжении, мы сможем рассмотреть пример с большими числами (это начинает ухудшаться на очень больших примерах).
Во-первых, нам нужен простой генератор простых чисел (примечание. На самом деле мы генерируем лог каждого простого числа).
И вот основная реализация:
Вот результаты применительно к
lst1, lst2, lst3, & lst (the large one)
данным @GKi.И вот некоторые тесты с
units
параметром, установленным вrelative
.Примерно в 3 раза быстрее, чем самое быстрое решение на большом примере.
Для меня этот результат говорит о красоте и эффективности,
base R
отображаемой @GKi, @ chinsoon12, @Gregor, @ThomasIsCoding и другими. Мы написали около 100 очень специфических строк,C++
чтобы получить умеренное ускорение. Чтобы быть справедливым,base R
решения в конечном итоге вызывают в основном скомпилированный код и используют хеш-таблицы, как мы делали выше.источник
После сортировки вы можете использовать
duplicated
иall
.Альтернатива: сортировка за один цикл
Альтернатива: сортировка во время цикла и возможность досрочного выхода
или используя
setequal
или немного улучшить идею от @ chinsoon12 обмениваться списком с вектором!
или избегать второго
order
или обмен
order
сmatch
(илиfmatch
)Или без досрочного выхода.
или написано на C ++
Спасибо @Gregor за подсказки, чтобы улучшить ответ!
источник
lst <- list(list(1,c(2,3,4),c(5,6),7), list(c(2,3,4),1,7,c(5,6)), list(1,c(2,3,4),7,c(6,5)), list(7,1,c(3,2,4),c(5,6)))
будет оцениваться какFALSE
min
!Представление:
Библиотеки:
Функции:
Данные:
источник
length(setdiff(Reduce(union,s),Reduce(intersect,s)))==0
, извините за мою ошибку ...Надеюсь, второй раз повезет
контрольные примеры:
проверки:
временный код:
тайминги:
источник