Java ArrayList - jak sprawdzić, czy dwie listy są równe, kolejność nie ma znaczenia?


140

Mam dwa ArrayListtypy Answer(klasa własna).

Chciałbym porównać dwie listy, aby sprawdzić, czy zawierają tę samą treść, ale bez znaczenia.

Przykład:

//These should be equal.
ArrayList<String> listA = {"a", "b", "c"}
ArrayList<String> listB = {"b", "c", "a"}

List.equalsstwierdza, że ​​dwie listy są równe, jeśli zawierają ten sam rozmiar, zawartość i kolejność elementów. Chcę tego samego, ale bez porządku.

Czy jest na to prosty sposób? A może będę musiał wykonać zagnieżdżoną pętlę for i ręcznie sprawdzić każdy indeks obu list?

Uwaga: nie mogę zmienić ich ArrayListna inny typ listy, muszą taką pozostać.


4
zobacz odpowiedź na to pytanie: stackoverflow.com/a/1075699/1133011
David Kroukamp

Zobacz List.containsAll (list) w java
Sahil Jain

Odpowiedzi:


134

Możesz posortować obie listy za pomocą, Collections.sort()a następnie użyć metody equals. Nieco lepszym rozwiązaniem jest najpierw sprawdzenie, czy mają tę samą długość przed zamówieniem, jeśli nie, to nie są równe, następnie posortuj, a następnie użyj równych. Na przykład, gdybyś miał dwie listy ciągów znaków, byłoby to coś takiego:

public  boolean equalLists(List<String> one, List<String> two){     
    if (one == null && two == null){
        return true;
    }

    if((one == null && two != null) 
      || one != null && two == null
      || one.size() != two.size()){
        return false;
    }

    //to avoid messing the order of the lists we will use a copy
    //as noted in comments by A. R. S.
    one = new ArrayList<String>(one); 
    two = new ArrayList<String>(two);   

    Collections.sort(one);
    Collections.sort(two);      
    return one.equals(two);
}

20
Pamiętaj tylko, aby nie zniszczyć kolejności oryginalnej listy (tak jak to Collections.sortrobi) - tj. Przekazać kopię.
arshajii

@ARS tak, to jest określony efekt uboczny, ale tylko wtedy, gdy ma to znaczenie w ich konkretnym przypadku.
Jacob Schoen

3
Możesz po prostu dodać, one = new ArrayList<String>(one); two = new ArrayList<String>(two);aby uniknąć zrujnowania argumentów.
arshajii

@jschoen Próba wykonania Collections.sort () daje mi następujący błąd: Niedopasowanie powiązania: Metoda ogólna sort (List <T>) typu Collections nie ma zastosowania dla argumentów (ArrayList <Answer>). Wywnioskowany typ Odpowiedź nie jest prawidłowym substytutem ograniczonego parametru <T rozszerza Porównywalne <? super T >>
iaacp

3
Drugą instrukcję "if" wewnątrz funkcji można uprościć, if(one == null || two == null || one.size() != two.size()){ return false; }ponieważ już sprawdzasz, czy zarówno jedno, jak i dwa są puste
Hugo

153

Prawdopodobnie najłatwiejszym sposobem na jakąkolwiek listę byłoby:

listA.containsAll(listB) && listB.containsAll(listA)

5
Gdzie w tym zabawa. Z całą powagą jest to jednak prawdopodobnie lepsze rozwiązanie.
Jacob Schoen

69
Zależy od tego, czy [a, b, c]i czy [c, b, a, b]mają taką samą zawartość. W tej odpowiedzi można by powiedzieć, że tak, ale może się zdarzyć, że w przypadku PO nie (ponieważ jeden zawiera duplikat, a drugi nie). Nie wspominając o problemach z wydajnością.
yshavit

4
ulepszanie na podstawie komentarzy - System.out.println (((l1.size () == l2.size ()) && l2.containsAll (l1) && l1.containsAll (l2)));
Nrj

8
@Nrj, a co z [1,2,2] i [2,1,1]?
ROMANIA_engineer

3
To podejście ma złożoność O (n ^ 2). Rozważ dwie listy, które są w odwrotnej kolejności, na przykład: [1,2,3] i [3,2,1]. Dla pierwszego elementu będzie musiał przeskanować n elementów, dla drugiego n-1 elementów i tak dalej. Więc złożoność będzie rzędu n ^ 2. Myślę, że lepszym sposobem będzie sortowanie, a następnie użycie równości. Będzie miał złożoność O (n * log (n))
puneet

93

Kolekcje Apache Commons ponownie na ratunek:

List<String> listA = Arrays.asList("a", "b", "b", "c");
List<String> listB = Arrays.asList("b", "c", "a", "b");
System.out.println(CollectionUtils.isEqualCollection(listA, listB)); // true

 

List<String> listC = Arrays.asList("a", "b", "c");
List<String> listD = Arrays.asList("a", "b", "c", "c");
System.out.println(CollectionUtils.isEqualCollection(listC, listD)); // false

Dokumenty:

org.apache.commons.collections4.CollectionUtils

public static boolean isEqualCollection(java.util.Collection a,
                                        java.util.Collection b)

Zwroty, truejeśli podane Collections zawierają dokładnie te same elementy z dokładnie takimi samymi licznościami.

To znaczy, jeśli liczność e w a jest równa liczności e w b , dla każdego elementu e w a lub b .

Parametry:

  • a - pierwsza kolekcja nie może być null
  • b - druga kolekcja nie może być null

Zwroty: truejeśli zbiory zawierają te same elementy o tych samych licznościach.


Implementacja wydaje się mniej więcej podobna do odpowiedzi DiddiZ.
user227353

OK ... ale co z złapaniem winowajców (elementów, które nie są wspólne dla obu list), jeśli odpowiedź brzmi false? Zobacz moją odpowiedź.
mike gryzoń

implementation 'org.apache.commons:commons-collections4:4.3'zostawił mi Caused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process ścieżkę błędu .
Aliton Oliveira

13
// helper class, so we don't have to do a whole lot of autoboxing
private static class Count {
    public int count = 0;
}

public boolean haveSameElements(final List<String> list1, final List<String> list2) {
    // (list1, list1) is always true
    if (list1 == list2) return true;

    // If either list is null, or the lengths are not equal, they can't possibly match 
    if (list1 == null || list2 == null || list1.size() != list2.size())
        return false;

    // (switch the two checks above if (null, null) should return false)

    Map<String, Count> counts = new HashMap<>();

    // Count the items in list1
    for (String item : list1) {
        if (!counts.containsKey(item)) counts.put(item, new Count());
        counts.get(item).count += 1;
    }

    // Subtract the count of items in list2
    for (String item : list2) {
        // If the map doesn't contain the item here, then this item wasn't in list1
        if (!counts.containsKey(item)) return false;
        counts.get(item).count -= 1;
    }

    // If any count is nonzero at this point, then the two lists don't match
    for (Map.Entry<String, Count> entry : counts.entrySet()) {
        if (entry.getValue().count != 0) return false;
    }

    return true;
}

Wow, byłem naprawdę zaskoczony, że to działa szybciej niż wszystkie inne rozwiązania. I obsługuje wczesne wyjście.
DiddiZ

Może to również spowodować zwarcie w drugiej pętli, jeśli stanie countsię ujemne, upraszczając korpus pętli do if(!counts.containsKey(item) || --counts.get(item).count < 0) return false;Ponadto trzecia pętla może zostać uproszczona dofor(Count c: counts.values()) if(c.count != 0) return false;
Holger

@Holger Rozważałem coś podobnego do pierwszego (usunięcie licznika, gdy osiągnie zero, co miałoby ten sam efekt, ale także zmieniłoby kontrole na końcu na „zwróć, czy countsjest puste”), ale nie chciałem tego zaciemniać główny punkt: użycie mapy zasadniczo zmienia to w problem O (N + M) i jest największym pojedynczym impulsem, jaki prawdopodobnie otrzymasz.
cHao

@cHao tak, zasługujesz na kredyty za wskazanie rozwiązania o większej złożoności czasowej niż poprzednie. Po prostu pomyślałem o tym, ponieważ ostatnio pojawiło się podobne pytanie dotyczące iterowalnych. Ponieważ mamy teraz również Javę 8, warto było to przemyśleć. Jeśli w drugiej pętli nastąpi zwarcie, gdy liczba stanie się ujemna, trzecia pętla stanie się przestarzała. Ponadto unikanie boksu może być mieczem obosiecznym, a nowe Map.merge, używanie liczb całkowitych w pudełku może być prostsze i bardziej wydajne w większości przypadków użycia. Zobacz także tę odpowiedź
Holger

12

Powiedziałbym, że te odpowiedzi pomijają sztuczkę.

Bloch w swojej podstawowej, cudownej, zwięzłej Efektywnej Javie , mówi w pozycji 47, zatytułowanej „Poznaj i używaj bibliotek”, „Podsumowując, nie odkrywaj na nowo koła”. I podaje kilka bardzo wyraźnych powodów, dla których nie.

Jest tutaj kilka odpowiedzi, które sugerują metody z CollectionUtilsbiblioteki Apache Commons Collections, ale żadna nie znalazła najpiękniejszego, najbardziej eleganckiego sposobu odpowiedzi na to pytanie :

Collection<Object> culprits = CollectionUtils.disjunction( list1, list2 );
if( ! culprits.isEmpty() ){
  // ... do something with the culprits, i.e. elements which are not common

}

Winowajcy : tj. Elementy, które nie są wspólne dla obu Lists. Określenie, do kogo należą, list1a do kogo winowajcy, list2jest stosunkowo proste przy użyciu CollectionUtils.intersection( list1, culprits )i CollectionUtils.intersection( list2, culprits ).
Jednak ma tendencję do rozpadania się w przypadkach takich jak {"a", "a", "b"} disjunctionz {"a", "b", "b"} ... z wyjątkiem tego, że nie jest to awaria oprogramowania, ale nieodłączne od charakteru subtelności / niejasności pożądanego zadania.

Zawsze możesz sprawdzić kod źródłowy (l. 287) dla takiego zadania, jak to zostało stworzone przez inżynierów Apache. Jedną z korzyści płynących z używania ich kodu jest to, że został on gruntownie wypróbowany i przetestowany, z wieloma skrajnymi przypadkami i problemami przewidzianymi i rozwiązanymi. W razie potrzeby możesz skopiować i ulepszyć ten kod według własnego uznania.


Uwaga: Na początku byłem rozczarowany, że żadna z CollectionUtilsmetod nie zapewnia przeładowanej wersji, umożliwiającej narzucenie własnej Comparator(dzięki czemu można przedefiniować equalsją tak, aby odpowiadała Twoim celom).

Ale z kolekcji4 4.0 jest nowa klasa, Equatorktóra „określa równość między obiektami typu T”. Podczas badania kodu źródłowego collections4 CollectionUtils.java wydaje się, że używają tego z niektórymi metodami, ale o ile wiem, nie ma to zastosowania do metod znajdujących się na początku pliku, przy użyciu CardinalityHelperklasy ... która obejmują disjunctioni intersection.

Przypuszczam, że ludzie z Apache jeszcze do tego nie doszli, ponieważ jest to nietrywialne: należałoby utworzyć coś w rodzaju klasy „AbstractEquatingCollection”, która zamiast używać elementów equalsi hashCodemetod jej elementów , musiałaby zamiast tego używać tych z Equatordla wszystkich podstawowych metod, takich jak add, containsitp. Uwaga: w rzeczywistości, gdy patrzysz na kod źródłowy, AbstractCollectionnie implementuje add, ani jego abstrakcyjnych podklas, takich jak AbstractSet... musisz poczekać, aż konkretne klasy takie jak HashSeti ArrayListwcześniej addjest zaimplementowane. Dość ból głowy.

Przypuszczam, że w międzyczasie obserwuj tę przestrzeń. Oczywistym tymczasowym rozwiązaniem byłoby umieszczenie wszystkich elementów w specjalnie zaprojektowanej klasie opakowania, która używa equalsi hashCodezaimplementuje taki rodzaj równości, jaki chcesz, a następnie manipulowanie Collectionstymi obiektami opakowania.


Również ktoś mądry powiedział: „Poznaj koszt zależności”
Stanisław Barański

@StanislawBaranski To ciekawy komentarz. Czy to sugestia, że ​​nie należy być zbyt zależnym od takich bibliotek? Kiedy używasz systemu operacyjnego na komputerze, to już ogromny skok wiary, prawda? Z przyjemnością korzystam z bibliotek Apache, ponieważ uważam, że są one rzeczywiście bardzo wysokiej jakości i zakładam, że ich metody są zgodne z ich „umową” i zostały gruntownie przetestowane. Ile czasu zajęłoby Ci opracowanie własnego kodu, któremu bardziej ufałeś? Skopiowanie kodu z bibliotek Apache o otwartym kodzie źródłowym i przeanalizowanie go może być czymś do przemyślenia ...
mike gryzoń

10

Jeśli liczność elementów nie ma znaczenia (co oznacza: powtarzające się elementy są uważane za jeden), można to zrobić bez konieczności sortowania:

boolean result = new HashSet<>(listA).equals(new HashSet<>(listB));

To utworzy SetOUT każdy List, a następnie za pomocą HashSet„S equalsmetodę, (oczywiście) pominięcia zamawiania.

Jeśli liczność ma znaczenie, musisz ograniczyć się do udogodnień zapewnianych przez List; W takim przypadku odpowiedź @ jschoen byłaby bardziej odpowiednia.


co jeśli listaA = [a, b, c, c] i listaB = [a, b, c]. wynik będzie prawdziwy, ale listy nie są równe.
Nikolas

6

Konwersja list do Multiset Guavy działa bardzo dobrze. Są one porównywane niezależnie od ich kolejności i uwzględniane są również zduplikowane elementy.

static <T> boolean equalsIgnoreOrder(List<T> a, List<T> b) {
    return ImmutableMultiset.copyOf(a).equals(ImmutableMultiset.copyOf(b));
}

assert equalsIgnoreOrder(ImmutableList.of(3, 1, 2), ImmutableList.of(2, 1, 3));
assert !equalsIgnoreOrder(ImmutableList.of(1), ImmutableList.of(1, 1));

6

Jest to oparte na rozwiązaniu @cHao. Dodałem kilka poprawek i ulepszeń wydajności. Działa to mniej więcej dwa razy szybciej niż rozwiązanie z równą zamówieniem kopii. Działa dla każdego typu kolekcji. Puste kolekcje i null są uważane za równe. Użyj na swoją korzyść;)

/**
 * Returns if both {@link Collection Collections} contains the same elements, in the same quantities, regardless of order and collection type.
 * <p>
 * Empty collections and {@code null} are regarded as equal.
 */
public static <T> boolean haveSameElements(Collection<T> col1, Collection<T> col2) {
    if (col1 == col2)
        return true;

    // If either list is null, return whether the other is empty
    if (col1 == null)
        return col2.isEmpty();
    if (col2 == null)
        return col1.isEmpty();

    // If lengths are not equal, they can't possibly match
    if (col1.size() != col2.size())
        return false;

    // Helper class, so we don't have to do a whole lot of autoboxing
    class Count
    {
        // Initialize as 1, as we would increment it anyway
        public int count = 1;
    }

    final Map<T, Count> counts = new HashMap<>();

    // Count the items in col1
    for (final T item : col1) {
        final Count count = counts.get(item);
        if (count != null)
            count.count++;
        else
            // If the map doesn't contain the item, put a new count
            counts.put(item, new Count());
    }

    // Subtract the count of items in col2
    for (final T item : col2) {
        final Count count = counts.get(item);
        // If the map doesn't contain the item, or the count is already reduced to 0, the lists are unequal 
        if (count == null || count.count == 0)
            return false;
        count.count--;
    }

    // At this point, both collections are equal.
    // Both have the same length, and for any counter to be unequal to zero, there would have to be an element in col2 which is not in col1, but this is checked in the second loop, as @holger pointed out.
    return true;
}

Możesz pominąć końcową pętlę for, używając licznika sum. Licznik sumy zlicza sumę zliczeń na każdym etapie. Zwiększ sumę licznika w pierwszej pętli for i zmniejsz ją w drugiej pętli for. Jeśli suma licznika jest większa niż 0, listy nie są zgodne, w przeciwnym razie tak. Obecnie w końcowej pętli for sprawdzasz, czy wszystkie zliczenia są równe zero, lub innymi słowy, czy suma wszystkich liczników wynosi zero. Użycie sumy licznika odwraca tę kontrolę, zwracając wartość true, jeśli suma zliczeń wynosi zero, lub false w przeciwnym razie.
SatA

IMO, warto ominąć tę pętlę for, ponieważ gdy listy są zgodne (najgorszy scenariusz), pętla for dodaje kolejne niepotrzebne O (n).
SatA

@SatA właściwie możesz usunąć trzecią pętlę bez wymiany. Druga pętla już powraca, falsegdy klucz nie istnieje lub jego liczba staje się ujemna. Ponieważ łączny rozmiar obu list jest zgodny (zostało to sprawdzone z góry), nie można mieć wartości niezerowych po drugiej pętli, ponieważ nie może istnieć dodatnich wartości dla klucza bez ujemnych wartości dla innego klucza.
Holger,

@holger, wygląda na to, że masz całkowitą rację. O ile wiem, trzecia pętla w ogóle nie jest konieczna.
SatA

@SatA… iw Javie 8 można to zaimplementować zwięźle, jak w tej odpowiedzi .
Holger

5

Pomyśl, jak byś to zrobił sam, nie mając komputera lub języka programowania. Podaję ci dwie listy elementów i musisz mi powiedzieć, czy zawierają te same elementy. Jak byś to zrobił?

Jedno podejście, jak wspomniano powyżej, polega na sortowaniu list, a następnie przechodzeniu je element po elemencie, aby sprawdzić, czy są równe (i tak List.equalsjest). Oznacza to, że albo możesz modyfikować listy, albo możesz je kopiować - i bez znajomości przypisania nie mogę wiedzieć, czy którekolwiek z nich są dozwolone.

Innym podejściem byłoby przejrzenie każdej listy i zliczenie, ile razy pojawia się każdy element. Jeśli obie listy mają na końcu te same liczby, mają te same elementy. Kodem do tego byłoby przetłumaczenie każdej listy na mapę, elem -> (# of times the elem appears in the list)a następnie wywołanie equalsdwóch map. Jeśli mapy są HashMap, każde z tych tłumaczeń jest operacją O (N), podobnie jak porównanie. To da ci całkiem wydajny algorytm pod względem czasu, kosztem dodatkowej pamięci.


5

Miałem ten sam problem i wpadłem na inne rozwiązanie. Ten działa również w przypadku duplikatów:

public static boolean equalsWithoutOrder(List<?> fst, List<?> snd){
  if(fst != null && snd != null){
    if(fst.size() == snd.size()){
      // create copied lists so the original list is not modified
      List<?> cfst = new ArrayList<Object>(fst);
      List<?> csnd = new ArrayList<Object>(snd);

      Iterator<?> ifst = cfst.iterator();
      boolean foundEqualObject;
      while( ifst.hasNext() ){
        Iterator<?> isnd = csnd.iterator();
        foundEqualObject = false;
        while( isnd.hasNext() ){
          if( ifst.next().equals(isnd.next()) ){
            ifst.remove();
            isnd.remove();
            foundEqualObject = true;
            break;
          }
        }

        if( !foundEqualObject ){
          // fail early
          break;
        }
      }
      if(cfst.isEmpty()){ //both temporary lists have the same size
        return true;
      }
    }
  }else if( fst == null && snd == null ){
    return true;
  }
  return false;
}

Zalety w porównaniu z niektórymi innymi rozwiązaniami:

  • mniejsza niż O (N²) złożoność (chociaż nie testowałem jego rzeczywistej wydajności w porównaniu z rozwiązaniami w innych odpowiedziach tutaj);
  • wychodzi wcześniej;
  • czeki pod kątem wartości zerowej;
  • działa nawet w przypadku duplikatów: jeśli masz tablicę [1,2,3,3]i inną tablicę, [1,2,2,3]większość rozwiązań mówi, że są one takie same, gdy nie rozważasz kolejności. To rozwiązanie pozwala tego uniknąć, usuwając równe elementy z tymczasowych list;
  • używa semantycznej równości ( equals) i nie odwołuje się do równości ( ==);
  • nie sortuje elementów, więc nie muszą być sortowalne (według implement Comparable), aby to rozwiązanie działało.

3

Jeśli nie masz nadziei na sortowanie zbiorów i potrzebujesz wyniku, że ["A" "B" "C"] nie jest równe ["B" "B" "A" "C"],

l1.containsAll(l2)&&l2.containsAll(l1)

to za mało, prawdopodobnie trzeba też sprawdzić rozmiar:

    List<String> l1 =Arrays.asList("A","A","B","C");
    List<String> l2 =Arrays.asList("A","B","C");
    List<String> l3 =Arrays.asList("A","B","C");

    System.out.println(l1.containsAll(l2)&&l2.containsAll(l1));//cautions, this will be true
    System.out.println(isListEqualsWithoutOrder(l1,l2));//false as expected

    System.out.println(l3.containsAll(l2)&&l2.containsAll(l3));//true as expected
    System.out.println(isListEqualsWithoutOrder(l2,l3));//true as expected


    public static boolean isListEqualsWithoutOrder(List<String> l1, List<String> l2) {
        return l1.size()==l2.size() && l1.containsAll(l2)&&l2.containsAll(l1);
}

2

Rozwiązanie wykorzystujące metodę odejmowania CollectionUtils:

import static org.apache.commons.collections15.CollectionUtils.subtract;

public class CollectionUtils {
  static public <T> boolean equals(Collection<? extends T> a, Collection<? extends T> b) {
    if (a == null && b == null)
      return true;
    if (a == null || b == null || a.size() != b.size())
      return false;
    return subtract(a, b).size() == 0 && subtract(a, b).size() == 0;
  }
}

1

Jeśli zależy Ci na porządku, skorzystaj z metody equals:

list1.equals(list2)

Jeśli nie obchodzi Cię kolejność, użyj tego

Collections.sort(list1);
Collections.sort(list2);      
list1.equals(list2)

5
Mówi, że nie dba o porządek.
mike gryzoń

0

Najlepsze z obu światów [@DiddiZ, @Chalkos]: ten opiera się głównie na metodzie @Chalkos, ale naprawia błąd (ifst.next ()) i poprawia wstępne testy (zaczerpnięte z @DiddiZ), a także eliminuje potrzebę skopiuj pierwszą kolekcję (po prostu usuwa elementy z kopii drugiej kolekcji).

Nie wymaga funkcji haszującej ani sortowania i umożliwiając wczesne istnienie braku równości, jest to najbardziej wydajna implementacja. Chyba że masz zbiór tysięcy lub więcej i bardzo prostą funkcję haszującą.

public static <T> boolean isCollectionMatch(Collection<T> one, Collection<T> two) {
    if (one == two)
        return true;

    // If either list is null, return whether the other is empty
    if (one == null)
        return two.isEmpty();
    if (two == null)
        return one.isEmpty();

    // If lengths are not equal, they can't possibly match
    if (one.size() != two.size())
        return false;

    // copy the second list, so it can be modified
    final List<T> ctwo = new ArrayList<>(two);

    for (T itm : one) {
        Iterator<T> it = ctwo.iterator();
        boolean gotEq = false;
        while (it.hasNext()) {
            if (itm.equals(it.next())) {
                it.remove();
                gotEq = true;
                break;
            }
        }
        if (!gotEq) return false;
    }
    // All elements in one were found in two, and they're the same size.
    return true;
}

Jeśli się nie mylę, złożoność tego algorytmu w scenariuszu wartym przypadku (gdzie listy są równe, ale posortowane w odwrotny sposób) wyniosłaby O (N * N!).
SatA,

Właściwie byłoby to O (N * (N / 2)), ponieważ z każdą iteracją rozmiar tablicy maleje.
jazzgil

0

Jest to alternatywny sposób sprawdzenia równości list tablic, które mogą zawierać wartości null:

List listA = Arrays.asList(null, "b", "c");
List listB = Arrays.asList("b", "c", null);

System.out.println(checkEquality(listA, listB)); // will return TRUE


private List<String> getSortedArrayList(List<String> arrayList)
{
    String[] array = arrayList.toArray(new String[arrayList.size()]);

    Arrays.sort(array, new Comparator<String>()
    {
        @Override
        public int compare(String o1, String o2)
        {
            if (o1 == null && o2 == null)
            {
                return 0;
            }
            if (o1 == null)
            {
                return 1;
            }
            if (o2 == null)
            {
                return -1;
            }
            return o1.compareTo(o2);
        }
    });

    return new ArrayList(Arrays.asList(array));
}

private Boolean checkEquality(List<String> listA, List<String> listB)
{
    listA = getSortedArrayList(listA);
    listB = getSortedArrayList(listB);

    String[] arrayA = listA.toArray(new String[listA.size()]);
    String[] arrayB = listB.toArray(new String[listB.size()]);

    return Arrays.deepEquals(arrayA, arrayB);
}

Jaki jest sens tego całego kopiowania między listami i tablicami?
Holger

0

Moje rozwiązanie na to. To nie jest takie fajne, ale działa dobrze.

public static boolean isEqualCollection(List<?> a, List<?> b) {

    if (a == null || b == null) {
        throw new NullPointerException("The list a and b must be not null.");
    }

    if (a.size() != b.size()) {
        return false;
    }

    List<?> bCopy = new ArrayList<Object>(b);

    for (int i = 0; i < a.size(); i++) {

        for (int j = 0; j < bCopy.size(); j++) {
            if (a.get(i).equals(bCopy.get(j))) {
                bCopy.remove(j);
                break;
            }
        }
    }

    return bCopy.isEmpty();
}

0

Metoda jednowierszowa :)

  1. Elementy kolekcji NIE implementują interfejsu Comparable <? super T>

     static boolean isEqualCollection(Collection<?> a, Collection<?> b) {
         return a == b || (a != null && b != null && a.size() == b.size()
             && a.stream().collect(Collectors.toMap(Function.identity(), s -> 1L, Long::sum)).equals(b.stream().collect(Collectors.toMap(Function.identity(), s -> 1L, Long::sum))));
     }
    
  2. Elementy kolekcji implementują interfejs Comparable <? super T>

     static <T extends Comparable<? super T>> boolean  isEqualCollection2(Collection<T> a, Collection<T> b) {
       return a == b || (a != null && b != null && a.size() == b.size() && a.stream().sorted().collect(Collectors.toList()).equals(b.stream().sorted().collect(Collectors.toList())));
     }
    
  3. obsługuje Android5 i Android6 przez https://github.com/retrostreams/android-retrostreams

    static boolean isEqualCollection(Collection<?> a, Collection<?> b) {
     return a == b || (a != null && b != null && a.size() == b.size()
             && StreamSupport.stream(a).collect(Collectors.toMap(Function.identity(), s->1L, Longs::sum)).equals(StreamSupport.stream(b).collect(Collectors.toMap(Function.identity(), s->1L, Longs::sum))));
    }
    

//// Przypadek testowy

    boolean isEquals1 = isEqualCollection(null, null); //true
    boolean isEquals2 = isEqualCollection(null, Arrays.asList("1", "2")); //false
    boolean isEquals3 = isEqualCollection(Arrays.asList("1", "2"), null); //false
    boolean isEquals4 = isEqualCollection(Arrays.asList("1", "2", "2"), Arrays.asList("1", "1", "2")); //false
    boolean isEquals5 = isEqualCollection(Arrays.asList("1", "2"), Arrays.asList("2", "1")); //true
    boolean isEquals6 = isEqualCollection(Arrays.asList("1", 2.0), Arrays.asList(2.0, "1")); //true
    boolean isEquals7 = isEqualCollection(Arrays.asList("1", 2.0, 100L), Arrays.asList(2.0, 100L, "1")); //true
    boolean isEquals8 = isEqualCollection(Arrays.asList("1", null, 2.0, 100L), Arrays.asList(2.0, null, 100L, "1")); //true

-1

W takim przypadku listy {"a", "b"} i {"b", "a"} są równe. A {"a", "b"} i {"b", "a", "c"} nie są równe. Jeśli korzystasz z listy obiektów złożonych, pamiętaj o nadpisaniu metody equals , ponieważ zawiera ją wewnątrz.

if (oneList.size() == secondList.size() && oneList.containsAll(secondList)){
        areEqual = true;
}

-1: daje złą odpowiedź z {"a", "a", "b"} i {"a", "b", "b"}: sprawdź kod źródłowy AbstractCollection.containsAll(). Musisz pozwolić na zduplikowane elementy, o których mówimy Lists, a nie o Sets. Zobacz moją odpowiedź.
mike gryzoń
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.