Prosty sposób na znalezienie, czy dwie różne listy zawierają dokładnie te same elementy?

Jaki jest najprostszy sposób, aby znaleźć, jeśli dwie listy zawierają dokładnie te same elementy, w standardowych bibliotekach Javy?

Nie powinno mieć znaczenia, czy te dwie listy są tą samą instancją, czy nie, i nie powinno mieć znaczenia, czy parametr type list jest inny.

Np.

List list1
List<String> list2; 
// ... construct etc

list1.add("A");
list2.add("A"); 
// the function, given these two lists, should return true

Pewnie coś mi się gapi w twarz wiem: -)


EDIT: dla wyjaśnienia, Szukałem dokładnie tych samych elementów i liczby elementów, w spokój.


EDIT: dzięki za wskazanie oczywistej odpowiedzi, której nie widziałem za szukanie : -)

Chociaż wszystkie odpowiedzi podane do tej pory są poprawne, niektóre są bardziej poprawne niż inne, więc poczekam chwilę na najlepszą zaokrągloną odpowiedź przed zaakceptowaniem.

Author: Grundlefleck, 2009-07-02

16 answers

Jeśli zależy ci na porządku, po prostu użyj metody equals:

list1.equals(list2)

Z javadoc:

Porównuje określony obiekt z ta lista równości. Zwraca true wtedy i tylko wtedy, gdy określony obiekt jest również listę, obie listy mają takie same rozmiar i wszystkie odpowiednie pary elementy na obu listach są równe. (Dwa pierwiastki e1 i e2 są równe, jeśli (e1= = null ? e2 = = null : e1.równa się(e2)).) Innymi słowy, dwa listy są zdefiniowane jako równe, jeśli są zawierają te same elementy w tym samym spokój. Definicja ta zapewnia, że metoda equals działa poprawnie w różnych implementacjach interfejs listy.

Jeśli chcesz sprawdzić niezależnie od kolejności, możesz skopiować wszystkie elementy do zestawów i użyć równości na wynikowych zestawach:

public static <T> boolean listEqualsIgnoreOrder(List<T> list1, List<T> list2) {
    return new HashSet<>(list1).equals(new HashSet<>(list2));
}

Ograniczenie tego podejścia polega na tym, że nie tylko ignoruje kolejność, ale także częstotliwość powielania elementów. Na przykład, jeśli list1 było ["A", "B"," A"] i list2 było ["A"," B"," B"] podejście Set uznałoby je za równe.

Jeśli musisz być niewrażliwy na kolejność, ale wrażliwy na częstotliwość duplikatów, możesz:

 275
Author: Laurence Gonsalves,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-29 06:42:46

Zamieściłem kilka rzeczy w komentarzach, myślę, że zasługuje na własną odpowiedź.

Jak wszyscy tutaj mówią, użycie equals () zależy od kolejności. Jeśli nie zależy ci na zamówieniu, masz 3 opcje.

Opcja 1

Użyj containsAll(). Ta opcja nie jest idealna, moim zdaniem, ponieważ oferuje najgorszą wydajność, O (N^2).

Opcja 2

Istnieją dwie odmiany tego:

2a) Jeśli nie zależy ci na utrzymaniu porządku twoich list... użyj Collections.sort() na obu listach. Następnie użyj equals(). Jest to O (nlogn), ponieważ robisz dwa rodzaje, a następnie porównanie O (n).

2b) Jeśli chcesz zachować kolejność 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.

Prowadzi to do:

Opcja 3

Jeśli Twoje wymagania są takie same jak część 2b , ale kopiowanie jest zbyt drogie. Możesz użyć zestawu drzew do sortowania za Ciebie. Zrzuć każdą listę do własnego zestawu drzew. Zostanie on posortowany w zestawie, a oryginalne listy pozostaną nienaruszone. Następnie wykonaj equals() Porównanie na obu TreeSet s. TreeSets s może być zbudowany w czasie O (nlogn), a equals() Jest O (n).

Wybierz: -).

edytuj: prawie zapomniałem o tym samym zastrzeżeniu, na które zwraca uwagę Laurence Gonsalves. Wdrożenie TreeSet wyeliminuje duplikaty. Jeśli zależy ci na duplikatach, będziesz potrzebował jakiegoś posortowanego multisetu.

 71
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:07

Jeśli używasz (lub chętnie używasz) kolekcji Apache Commons, możesz użyć CollectionUtils.isEqualCollection, która " zwraca true iff dane zbiory zawierają dokładnie te same elementy o dokładnie tych samych cechach kardynalnych."

 9
Author: megaflop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-01 12:20:56

Wiem, że to stary wątek, ale żadna z innych odpowiedzi nie rozwiązała w pełni mojego przypadku użycia(myślę, że Guava Multiset może zrobić to samo, ale nie ma tutaj przykładu). Proszę wybaczyć moje formatowanie. Nadal jestem nowy w publikowaniu na stack exchange. Dodatkowo daj mi znać, jeśli są jakieś błędy

Powiedzmy, że masz List<T> a i List<T> b i chcesz sprawdzić, czy są one równe następującym warunkom:

1) O(n) oczekiwany czas pracy
2) równość definiowana jest jako: dla wszystkich elementy w a lub b, Liczba wystąpień elementu w a jest równa liczbie wystąpień elementu w b. równość elementu jest zdefiniowana jako T. equals ()

private boolean listsAreEquivelent(List<? extends Object> a, List<? extends Object> b) {
    if(a==null) {
        if(b==null) {
            //Here 2 null lists are equivelent. You may want to change this.
            return true;
        } else {
            return false;
        }
    }
    if(b==null) {
        return false;
    }
    Map<Object, Integer> tempMap = new HashMap<>();
    for(Object element : a) {
        Integer currentCount = tempMap.get(element);
        if(currentCount == null) {
            tempMap.put(element, 1);
        } else {
            tempMap.put(element, currentCount+1);
        }
    }
    for(Object element : b) {
        Integer currentCount = tempMap.get(element);
        if(currentCount == null) {
            return false;
        } else {
            tempMap.put(element, currentCount-1);
        }
    }
    for(Integer count : tempMap.values()) {
        if(count != 0) {
            return false;
        }
    }
    return true;
}

Czas pracy wynosi O(n), ponieważ wykonujemy o(2*n) wstawianie do hashmapy i O (3*N) wybór hashmapy. Nie do końca przetestowałem ten kod, więc uważaj :)

//Returns true:
listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("B","A","A"));
listsAreEquivelent(null,null);
//Returns false:
listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("B","A","B"));
listsAreEquivelent(Arrays.asList("A","A","B"),Arrays.asList("A","B"));
listsAreEquivelent(Arrays.asList("A","A","B"),null);
 6
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-23 21:09:03

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.

public boolean arraysMatch(List<String> elements1, List<String> elements2) {
    // Optional quick test since size must match
    if (elements1.size() != elements2.size()) {
        return false;
    }
    List<String> work = newArrayList(elements2);
    for (String element : elements1) {
        if (!work.remove(element)) {
            return false;
        }
    }
    return work.isEmpty();
}
 4
Author: Lee Meador,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 19:11:12

Bardzo późno na imprezę, ale chciałem dodać ten null safe check:

Objects.equals(list1, list2)
 4
Author: Reimeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 18:41:43

Rozwiązanie dla przypadku, gdy dwie listy mają te same elementy, ale różną kolejność:

public boolean isDifferentLists(List<Integer> listOne, List<Integer> listTwo) {
    if(isNullLists(listOne, listTwo)) {
        return false;
    }

    if (hasDifferentSize(listOne, listTwo)) {
        return true;
    }

    List<Integer> listOneCopy = Lists.newArrayList(listOne);
    List<Integer> listTwoCopy = Lists.newArrayList(listTwo);
    listOneCopy.removeAll(listTwoCopy);

    return CollectionUtils.isNotEmpty(listOneCopy);
}

private boolean isNullLists(List<Integer> listOne, List<Integer> listTwo) {
    return listOne == null && listTwo == null;
}

private boolean hasDifferentSize(List<Integer> listOne, List<Integer> listTwo) {
    return (listOne == null && listTwo != null) || (listOne != null && listTwo == null) || (listOne.size() != listTwo.size());
}
 2
Author: Pavlo Zvarych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-31 12:44:36

Odpowiedź Toma jest doskonała zgadzam się w pełni z jego odpowiedziami!

Interesującym aspektem tego pytania jest to, czy potrzebny jest sam typ List i jego nieodłączna kolejność.

Jeśli nie, możesz zdegradować do Iterable lub Collection, co daje Ci pewną elastyczność w przekazywaniu struktur danych, które są sortowane w czasie wstawiania, a nie w czasie, w którym chcesz to sprawdzić.

Jeśli kolejność nie ma znaczenia (i nie masz duplikatów elementów) rozważ użycie Set.

Jeśli kolejność ma znaczenie, ale jest określona przez czas wstawiania (a nie masz duplikatów) rozważ LinkedHashSet, który jest podobny do zbioru drzew, ale jest uporządkowany według czasu wstawiania (duplikaty nie są liczone). To również daje O(1) amortyzowany dostęp do O(log n).

 2
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 15:17:34

Metoda equals na liście zrobi to, Listy są uporządkowane, więc aby były równe, dwie listy muszą mieć te same elementy w tej samej kolejności.

return list1.equals(list2);
 1
Author: daveb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 17:27:26
list1.equals(list2);

Jeśli Twoja lista zawiera niestandardową klasę MyClass, ta klasa musi nadpisać funkcję equals.

 class MyClass
  {
  int field=0;
  @0verride
  public boolean equals(Object other)
        {
        if(this==other) return true;
        if(other==null || !(other instanceof MyClass)) return false;
        return this.field== MyClass.class.cast(other);
        }
  }

Uwaga: Jeśli chcesz przetestować equals na Javie.util.Ustaw zamiast java.util.List, wtedy twój obiekt musi nadpisać funkcję hashCode.

 1
Author: Pierre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 17:31:43

Przykładowy kod:

public static '<'T'>' boolean isListDifferent(List'<'T'>' previousList,
        List'<'T'>' newList) {

    int sizePrevoisList = -1;
    int sizeNewList = -1;

    if (previousList != null && !previousList.isEmpty()) {
        sizePrevoisList = previousList.size();
    }
    if (newList != null && !newList.isEmpty()) {
        sizeNewList = newList.size();
    }

    if ((sizePrevoisList == -1) && (sizeNewList == -1)) {
        return false;
    }

    if (sizeNewList != sizePrevoisList) {
        return true;
    }

    List n_prevois = new ArrayList(previousList);
    List n_new = new ArrayList(newList);

    try {
        Collections.sort(n_prevois);
        Collections.sort(n_new);
    } catch (ClassCastException exp) {
        return true;
    }

    for (int i = 0; i < sizeNewList; i++) {
        Object obj_prevois = n_prevois.get(i);
        Object obj_new = n_new.get(i);
        if (obj_new.equals(obj_prevois)) {
            // Object are same
        } else {
            return true;
        }
    }

    return false;
}
 1
Author: Jaydip Halake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 09:55:55

Oprócz odpowiedzi Laurence ' a, jeśli chcesz, aby była bezpieczna dla null:

private static <T> boolean listEqualsIgnoreOrder(List<T> list1, List<T> list2) {
    if (list1 == null)
        return list2==null;
    if (list2 == null)
        return list1 == null;
    return new HashSet<>(list1).equals(new HashSet<>(list2));
}
 1
Author: Felixuko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-05 15:31:11
 0
Author: Jeremy Smyth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 17:26:30

Możesz użyć org Apache ' a.Apacz.commons.biblioteka zbiorów: http://commons.apache.org/collections/apidocs/org/apache/commons/collections/ListUtils.html

public static boolean isEqualList(java.util.Collection list1,
                              java.util.Collection list2)
 0
Author: David Zhao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-03 07:36:24

Sprawdź, czy obie listy nie są null. Jeśli ich rozmiary są różne, to listy te nie są sobie 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ą nullami, uważam je za równe.

private boolean compareLists(List<?> l1, List<?> l2) {
    if (l1 == null && l2 == null) {
        return true;
    } else if (l1 == null || l2 == null) {
        return false;
    }

    if (l1.size() != l2.size()) {
        return false;
    }

    Map<?, Integer> m1 = toMap(l1);
    Map<?, Integer> m2 = toMap(l2);

    return m1.equals(m2);
}

private Map<Object, Integer> toMap(List<?> list) {
    //Effective size, not to resize in the future.
    int mapSize = (int) (list.size() / 0.75 + 1);
    Map<Object, Integer> map = new HashMap<>(mapSize);

    for (Object o : list) {
        Integer count = map.get(o);
        if (count == null) {
            map.put(o, 1);
        } else {
            map.put(o, ++count);
        }
    }

    System.out.println(map);
    return map;
}

Proszę zauważyć, że metoda równa powinna być poprawnie zdefiniowana dla tych obiektów. https://stackoverflow.com/a/24814634/4587961

 0
Author: Yan Khonski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-21 20:51:11

To zależy od tego, jakiej konkretnej klasy listy używasz. Klasa abstrakcyjna AbstractCollection ma metodę o nazwie containsAll (Collection), która pobiera inny zbiór ( lista jest zbiorem) i:

Zwraca true, jeśli ta kolekcja zawiera wszystkie elementy w podanej kolekcji.

Więc jeśli ArrayList jest przekazywana w można wywołać tę metodę, aby sprawdzić, czy są one dokładnie takie same.

       List foo = new ArrayList();
    List bar = new ArrayList();
    String str = "foobar";

    foo.add(str);
    bar.add(str);

    foo.containsAll(bar);

Powodem containsAll() jest to, że przechodzi przez pierwszą listę szukając dopasowania na drugiej liście. Więc jeśli są one nie w porządku, equals() nie odbierze go.

Edytuj: Chcę tylko skomentować tutaj amortyzowany czas wykonywania różnych oferowanych opcji. Czy czas pracy jest ważny? Jasne. Czy to jedyna rzecz, którą powinieneś rozważyć? Nie.

Koszt kopiowania każdego pojedynczego elementu z listy do innych list wymaga 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 jest problemem (co powinno być ogólnie), nadal musisz wziąć pod uwagę czas potrzebny na skopiowanie każdego elementu z dwóch list do dwóch zestawów drzew. Pamiętaj, że sortuje każdy element, gdy wchodzi do nich.

Moja ostatnia rada? Musisz wziąć pod uwagę swój zestaw danych i ile elementów masz w zestawie danych, a także jak duży jest każdy obiekt w zestawie danych, zanim będziesz mógł podjąć dobrą decyzję proszę. Baw się nimi, stwórz po jednym w każdą stronę i zobacz, który z nich działa szybciej. To dobre ćwiczenie.
 -2
Author: amischiefr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 18:06:04