Jaki jest najprostszy sposób na sprawdzenie, czy dwie listy zawierają dokładnie takie same elementy w standardowych bibliotekach Java?
Nie powinno mieć znaczenia, czy dwie listy są tym samym wystąpieniem, czy nie, i nie powinno mieć znaczenia, czy parametr typu list jest inny.
na przykład
List list1
List<String> list2;
// ... construct etc
list1.add("A");
list2.add("A");
// the function, given these two lists, should return true
Prawdopodobnie coś wpatruje się we mnie w twarz, którą znam :-)
EDYCJA: Aby wyjaśnić, szukałem DOKŁADNIE tych samych elementów i ich liczby, w kolejności.
java
collections
Grundlefleck
źródło
źródło
Odpowiedzi:
Jeśli zależy Ci na porządku, skorzystaj z metody równości:
Z javadoc:
Jeśli chcesz sprawdzić niezależnie od kolejności, możesz skopiować wszystkie elementy do zestawów i użyć równości w wynikowych zestawach:
Ograniczeniem tego podejścia jest to, że nie tylko ignoruje porządek, ale także częstotliwość zduplikowanych elementów. Na przykład, jeśli
list1
było [„A”, „B”, „A”] ilist2
było [„A”, „B”, „B”],Set
podejście uznałoby je za równe.Jeśli chcesz być niewrażliwy na zamówienie, ale wrażliwy na częstotliwość duplikatów, możesz:
źródło
a = [x, y, x]
ab = [x, y, z]
następnie rozmiary są równe ib.containsAll(a)
zwróci wartość true, aleb
zawiera element, którego nie ma wa
.W komentarzach zamieściłem wiele rzeczy, które, jak sądzę, wymagają własnej odpowiedzi.
Jak wszyscy tu mówią, użycie equals () zależy od kolejności. Jeśli nie zależy ci na porządku, masz 3 opcje.
opcja 1
Zastosowanie
containsAll()
. Moim zdaniem ta opcja nie jest idealna, ponieważ oferuje najgorszą wydajność, O (n ^ 2).Opcja 2
Istnieją dwie wersje:
2a) Jeśli nie zależy ci na utrzymaniu porządku na twoich listach ... użyj
Collections.sort()
na obu listach. Następnie użyjequals()
. To jest O (nlogn), ponieważ robisz dwa rodzaje, a następnie porównujesz O (n).2b) Jeśli chcesz zachować porządek list, możesz najpierw skopiować obie listy. NASTĘPNIE możesz użyć rozwiązania 2a na obu skopiowanych listach. Jednak może to być nieatrakcyjne, jeśli kopiowanie jest bardzo drogie.
To prowadzi do:
Opcja 3
Jeśli twoje wymagania są takie same jak w części 2b , ale kopiowanie jest zbyt drogie. Możesz użyć TreeSet, aby wykonać sortowanie. Zrzuć każdą listę do własnego TreeSet. Zostanie on posortowany w zestawie, a oryginalne listy pozostaną nienaruszone. Następnie wykonaj
equals()
porównanie obuTreeSet
s. DoTreeSets
S może być zbudowany w O (nlogn) czas, aequals()
O (n).Wybierz :-).
EDYCJA: Prawie zapomniałem tego samego zastrzeżenia, na którewskazuje Laurence Gonsalves . Implementacja TreeSet wyeliminuje duplikaty. Jeśli zależy Ci na duplikatach, będziesz potrzebować sortowanego multiset.
źródło
a.containsAll(b) && b.containsAll(a)
Jeśli używasz (lub z przyjemnością używasz) kolekcji Apache Commons, możesz użyć CollectionUtils.isEqualCollection, która „zwraca wartość prawdy, jeśli podane kolekcje zawierają dokładnie te same elementy o dokładnie takich samych licznościach”.
źródło
Bardzo późno na imprezę, ale chciałem dodać tę zerową kontrolę bezpieczeństwa:
źródło
Wiem, że to stary wątek, ale żadna z pozostałych odpowiedzi nie rozwiązała w pełni mojego przypadku użycia (wydaje mi się, że Guava Multiset może zrobić to samo, ale nie ma tutaj żadnego przykładu). Przepraszam za moje formatowanie. Nadal jestem nowy w publikowaniu na stosie wymiany. Dodatkowo daj mi znać, jeśli są jakieś błędy
Powiedzmy, że masz
List<T>
a iList<T>
b i chcesz sprawdzić, czy są one równe z następujących warunków:1) O (n) oczekiwany czas działania
2) Równość jest zdefiniowana jako: Dla wszystkich elementów w a lub b liczba wystąpień elementu w a jest równa liczbie wystąpień elementu w b. Równość elementów jest zdefiniowana jako T.equals ()
Czas działania to O (n), ponieważ wykonujemy wstawiania O (2 * n) do mapy skrótów i zaznaczanie mapy skrótów O (3 * n) wybiera. Nie w pełni przetestowałem ten kod, więc uważaj :)
źródło
Wypróbuj tę wersję, która nie wymaga, aby kolejność była taka sama, ale obsługuje wielokrotność tej samej wartości. Pasują tylko wtedy, gdy każdy ma taką samą ilość dowolnej wartości.
źródło
Metoda równości na liście to zrobi, listy są uporządkowane, więc aby były równe, dwie listy muszą mieć te same elementy w tej samej kolejności.
źródło
Rozwiązanie na wypadek, gdy dwie listy mają te same elementy, ale w innej kolejności:
źródło
removeAll()
zamiast tegocontainsAll()
(rozumiem, że jeśli listTwo zawiera duplikaty, które są zawarte tylko raz w listOne, podejście zawieraAll () nieprawidłowo zgłasza listy jako równe).Odpowiedź Toma jest doskonała. W pełni zgadzam się z jego odpowiedziami!
Ciekawym aspektem tego pytania jest to, czy potrzebujesz samego
List
typu i jego właściwego uporządkowania.Jeśli nie, możesz zdegradować
Iterable
lubCollection
dać ci pewną elastyczność w przekazywaniu struktur danych sortowanych według czasu wstawiania, a nie w czasie, gdy chcesz to sprawdzić.Jeśli kolejność nigdy nie ma znaczenia (a nie masz zduplikowanych elementów), rozważ użycie
Set
.Jeśli kolejność ma znaczenie, ale jest zdefiniowana przez czas wstawiania (i nie masz duplikatów), rozważ taki,
LinkedHashSet
który jest podobny do TreeSet, ale jest uporządkowany według czasu wstawienia (duplikaty nie są liczone). Daje to równieżO(1)
dostęp amortyzowanyO(log n)
.źródło
Przykładowy kod:
źródło
Oprócz odpowiedzi Laurence'a, jeśli chcesz również uczynić ją bezpieczną:
źródło
if (list1 == null) return list2==null; if (list2 == null) return false;
Jeśli twoja lista zawiera niestandardową klasę MyClass, ta klasa musi zastąpić
equals
funkcję.Uwaga: jeśli chcesz testować na java.util.Set zamiast na a
java.util.List
, twój obiekt musi zastąpićhashCode
funkcję.źródło
List.equals ()
http://java.sun.com/j2se/1.5/docs/api/java/util/List.html#equals(java.lang.Object)
źródło
Możesz użyć biblioteki org.apache.commons.collections Apache: http://commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html
źródło
Sprawdź, czy obie listy nie są zerami. Jeśli ich rozmiary są różne, listy te nie są równe. Twórz mapy składające się z elementów list jako kluczy i ich powtórzeń jako wartości i porównuj mapy.
Założenia, jeśli obie listy są zerowe, uważam je za równe.
Uwaga: metoda równa powinna być poprawnie zdefiniowana dla tych obiektów. https://stackoverflow.com/a/24814634/4587961
źródło
[x, x, y]
Vs[x, y, y]
zwróci wartość true z twoją implementacją.To zależy od tego, jakiej konkretnej klasy List używasz. Klasa abstrakcyjna AbstractCollection ma metodę o nazwie zawieraAll (kolekcja), która pobiera inną kolekcję (lista to kolekcja) i:
Więc jeśli przekazywana jest ArrayList, możesz wywołać tę metodę, aby zobaczyć, czy są one dokładnie takie same.
Powodem funkcji zawieraAll () jest to, że iteruje pierwszą listę szukając dopasowania na drugiej liście. Więc jeśli nie działają, równy () nie odbierze.
EDYCJA: Chcę tylko skomentować tutaj o zamortyzowanym czasie wykonywania różnych oferowanych opcji. Czy czas pracy jest ważny? Pewnie. Czy to jedyna rzecz, którą powinieneś rozważyć? Nie.
Koszt skopiowania KAŻDEGO pojedynczego elementu z twoich list na inne listy zajmuje dużo czasu, a także zajmuje sporą część pamięci (skutecznie podwajając pamięć, której używasz).
Więc jeśli pamięć w JVM nie stanowi problemu (co powinno być w zasadzie), to nadal musisz wziąć pod uwagę czas potrzebny do skopiowania każdego elementu z dwóch list do dwóch TreeSets. Pamiętaj, że sortuje każdy element, gdy wchodzi do nich.
Moja ostatnia rada? Musisz rozważyć swój zestaw danych i liczbę elementów, które masz w zestawie danych, a także jak duży jest każdy obiekt w zestawie danych, zanim podejmiesz tutaj dobrą decyzję. Baw się z nimi, stwórz je w jedną stronę i zobacz, która z nich działa szybciej. To dobre ćwiczenie.
źródło