Tutaj mam liczby całkowite 1:7
dla czterech różnych partycji, tj. {1}, {2,3,4}, {5,6} i {7}, a te partycje są zapisane na liście, tj list(1,c(2,3,4),c(5,6),7)
. Traktuję partycje jak zestawy, tak że różne permutacje elementów w obrębie jednej partycji powinny być rozpoznawane jako ta sama. Na przykład list(1,c(2,3,4),c(5,6),7)
i list(7,1,c(2,3,4),c(6,5))
są równoważne.
Zauważ, że nie ma powtórzeń dla elementów na liście, np. Nie list(c(1,2),c(2,1),c(1,2))
, ponieważ problemem jest omawianie wyłącznych partycji w całym zestawie.
Wymieniłem niektóre z różnych permutacji na liście, lst
jak poniżej
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)))
i chcę sprawdzić, czy wszystkie permutacje są równoważne. Jeśli tak, to otrzymamy wynik TRUE
.
Co zrobiłem tak daleko jest do sortowania elementów w każdej partycji, a używany setdiff()
z interset()
i union()
aby ją ocenić (patrz mój kod poniżej)
s <- Map(function(v) Map(sort,v),lst)
equivalent <- length(setdiff(Reduce(union,s),Reduce(intersect,s),))==0
Jednak myślę, że ta metoda byłaby wolna, ilekroć rozmiar partycji zostanie zwiększony. Czy jest jakieś szybsze podejście, aby to zrobić? Doceniany z góry!
- niektóre przypadki testowe (dane o małym rozmiarze)
# 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)))
źródło
Map
połączeńlst_equal = list(list(1:2, 3:4), list(3:4, 1:2))
a także taki, w którym wynik powinien byćFALSE
, być możelst_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
. W ten sposób, gdy odpowiedź działa na niektórych, ale nie wszystkich przypadkach testowych, łatwo zdiagnozować dlaczego. Gdy jest tylko jeden przykład, tracisz niuans w wynikach testu. Przyjemnie jest też dodawać nowe przykłady, zamiast zmieniać istniejące przykłady pod osobami, które już nad nimi pracowały.lst
jest potencjalnie długa, możesz zyskać na wydajności przy innych podejściach. Np. Pierwsza kontrola,length(unique(lengths(lst))) == 1
która bardzo szybko powróciłaby,FALSE
gdyby którakolwiek z wewnętrznych list zawierała nieprawidłową liczbę elementów ....lst
porównująclst[[i]]
dolst[[1]]
, i w ten sposób można zatrzymać jak najszybciej znaleźć niedopasowania, zamiast robić wszystkich porównań. Jeślilst
jest długi, aFALSE
s są powszechne, może to być duży wzrost wydajności, ale prawdopodobnie nie jest tego wart.Odpowiedzi:
Wpis o
R
i każdy wariant postu nie byłby kompletny bez rozwiązania z rcpp .Aby zmaksymalizować wydajność, niezwykle ważne będzie wybranie odpowiedniej struktury danych. Nasza struktura danych musi przechowywać unikalne wartości, a także mieć szybkie wstawianie / dostęp. To jest dokładnie to, co std :: unordered_set ucieleśnia . Musimy jedynie ustalić, w jaki sposób możemy jednoznacznie zidentyfikować każdego
vector
z nieuporządkowanychintegers
.Wejdz do podstawowe twierdzenie arytmetyki
Umowa o wolnym handlu stanowi, że każdą liczbę można jednoznacznie przedstawić (do rzędu czynników) przez iloczyn liczb pierwszych.
Oto przykład pokazujący, jak możemy skorzystać z umowy o wolnym handlu, aby szybko odszyfrować, czy dwa wektory są równoważne w kolejności (uwaga
P
poniżej: lista liczb pierwszych ...(2, 3, 5, 7, 11, etc.)
:Z tego widzimy to
vec1
ivec3
poprawnie mapujemy na ten sam numer, a jednocześnievec2
mapujemy na inną wartość.Ponieważ nasze rzeczywiste wektory mogą zawierać do stu liczb całkowitych mniejszych niż 1000, zastosowanie FTA da bardzo duże liczby. Możemy to obejść, korzystając z logarytmu reguły produktu:
Mając to do dyspozycji, będziemy w stanie poradzić sobie z przykładem o znacznie większej liczbie (zaczyna się to pogarszać na bardzo dużych przykładach).
Po pierwsze, potrzebujemy prostego generatora liczb pierwszych (uwaga: W rzeczywistości generujemy log każdej liczby pierwszej).
A oto główne wdrożenie:
Oto wyniki po zastosowaniu
lst1, lst2, lst3, & lst (the large one)
przez @GKi.A oto niektóre testy porównawcze z
units
parametrem ustawionym narelative
.Około 3 razy szybsze niż najszybsze rozwiązanie na większym przykładzie.
Dla mnie ten wynik
base R
świadczy o pięknie i wydajności wyświetlanych przez @GKi, @ chinsoon12, @Gregor, @ThomasIsCoding i więcej. Napisaliśmy około 100 wierszy bardzo specyficznych,C++
aby uzyskać umiarkowane przyspieszenie. Szczerzebase R
mówiąc , rozwiązania wywołują głównie skompilowany kod i wykorzystują tabele skrótów, jak to zrobiliśmy powyżej.źródło
Po posortowaniu możesz użyć
duplicated
iall
.Alternatywnie: Sortuj w jednej pętli
Alternatywa: Sortuj podczas pętli i zezwól na wcześniejsze wyjście
lub za pomocą
setequal
lub nieznacznie ulepszając pomysł @ chinsoon12, aby wymienić listę na wektorze!
lub unikaj drugiego
order
lub wymień
order
zmatch
(lubfmatch
)Lub bez wcześniejszego wyjścia.
lub napisane w C ++
Dziękujemy @Gregor za wskazówki, które pomogą poprawić odpowiedź!
źródło
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)))
będzie oceniany jakoFALSE
min
!Wydajność:
Biblioteki:
Funkcje:
Dane:
źródło
length(setdiff(Reduce(union,s),Reduce(intersect,s)))==0
, przepraszam za mój błąd ....Mam nadzieję, że szczęście po raz drugi
przypadki testowe:
czeki:
kod czasowy:
czasy:
źródło