Java ArrayList - làm thế nào tôi có thể biết nếu hai danh sách bằng nhau, thứ tự không quan trọng?


133

Tôi có hai ArrayListloại Answer(lớp tự làm).

Tôi muốn so sánh hai danh sách để xem chúng có chứa cùng một nội dung không, nhưng không có vấn đề gì.

Thí dụ:

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

List.equalsnói rằng hai danh sách bằng nhau nếu chúng có cùng kích thước, nội dung và thứ tự các phần tử. Tôi muốn điều tương tự, nhưng không có vấn đề trật tự.

Có một cách đơn giản để làm điều này? Hoặc tôi sẽ cần phải thực hiện một vòng lặp lồng nhau và kiểm tra thủ công từng chỉ mục của cả hai danh sách?

Lưu ý: Tôi không thể thay đổi chúng từ ArrayListloại danh sách khác, chúng cần giữ nguyên danh sách đó.


4
xem câu trả lời cho câu hỏi này: stackoverflow.com/a/1075699/1133011
David Kroukamp

Xem List.contains ALL (danh sách) trong java
Sahil Jain

Câu trả lời:


130

Bạn có thể sắp xếp cả hai danh sách bằng cách sử dụng Collections.sort()và sau đó sử dụng phương thức bằng. Một giải pháp tốt hơn là trước tiên hãy kiểm tra xem chúng có cùng độ dài trước khi đặt hàng hay không, nếu chúng không bằng nhau, sau đó sắp xếp, sau đó sử dụng bằng. Ví dụ: nếu bạn có hai danh sách Chuỗi, nó sẽ giống như:

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
Chỉ cần nhớ không phá hủy thứ tự của danh sách gốc (như Collections.sortvậy) - tức là vượt qua một bản sao.
arshajii

@ARS có, đó là một tác dụng phụ nhất định, nhưng chỉ khi nó quan trọng trong trường hợp cụ thể của họ.
Jacob Schoen

3
Bạn chỉ có thể thêm one = new ArrayList<String>(one); two = new ArrayList<String>(two);để tránh làm hỏng các đối số.
arshajii

@jschoen Cố gắng thực hiện Collections.sort () đang đưa ra lỗi này: Bound mismatch: Sắp xếp phương thức chung (Danh sách <T>) của loại Bộ sưu tập không áp dụng cho các đối số (ArrayList <Trả lời>). Loại câu trả lời được suy ra không phải là sự thay thế hợp lệ cho tham số giới hạn <T mở rộng so sánh <? siêu T >>
iaacp

3
Hàm "if" thứ hai bên trong hàm có thể được đơn giản hóa if(one == null || two == null || one.size() != two.size()){ return false; }vì bạn đã kiểm tra xem cả một và hai có rỗng hay không
Hugo

151

Có lẽ cách dễ nhất cho bất kỳ danh sách sẽ là:

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

5
Đâu là niềm vui trong đó. Trong tất cả sự nghiêm túc mặc dù đây có lẽ là giải pháp tốt hơn.
Jacob Schoen

67
Phụ thuộc vào việc [a, b, c][c, b, a, b]được coi là có cùng nội dung. Câu trả lời này sẽ nói họ làm, nhưng có thể là vì OP họ không (vì cái này chứa một bản sao còn cái kia thì không). Không nói gì đến vấn đề hiệu quả.
yshavit

4
nâng cao dựa trên nhận xét - System.out.println (((l1.size () == l2.size ()) && l2.contains ALL (l1) && l1.contains ALL (l2)));
Nrj

8
@Nrj, còn [1,2,2] và [2,1,1] thì sao?
ROMANIA_engineer

3
Cách tiếp cận này có độ phức tạp của O (n ^ 2). Xem xét hai danh sách theo thứ tự ngược lại, ví dụ: [1,2,3] và [3,2,1]. Đối với phần tử đầu tiên, nó sẽ phải quét n phần tử, cho phần tử n-1 thứ hai, v.v. Vì vậy, sự phức tạp sẽ có thứ tự n ^ 2. Tôi nghĩ cách tốt hơn sẽ là sắp xếp và sau đó sử dụng bằng. Nó sẽ có độ phức tạp của O (n * log (n))
phạt

90

Bộ sưu tập Apache Commons để giải cứu một lần nữa:

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

Tài liệu:

org.apache.commons.collections4.CollectionUtils

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

Trả về trueiff các Collections đã cho chứa chính xác các phần tử có cùng số lượng chính xác.

Nghĩa là, nếu số lượng của e trong a bằng với số lượng của e trong b , cho mỗi phần tử e trong a hoặc b .

Thông số:

  • a - bộ sưu tập đầu tiên, không được null
  • b - bộ sưu tập thứ hai, không được null

Trả về: trueiff các bộ sưu tập chứa các phần tử giống nhau có cùng số lượng.


Việc thực hiện có vẻ ít nhiều giống với câu trả lời của DiddiZ.
227353 27/8/2015

OK ... nhưng những gì về việc nắm giữ các thủ phạm (yếu tố không phổ biến trong hai danh sách) nếu câu trả lời là false? Xem câu trả lời của tôi.
mike gặm nhấm

implementation 'org.apache.commons:commons-collections4:4.3'đã để lại cho tôi một Caused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process đường dẫn lỗi .
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, thực sự ngạc nhiên khi thấy điều này thực hiện nhanh hơn tất cả các giải pháp khác. Và nó hỗ trợ ra sớm.
DiddiZ

Điều này cũng có thể ngắn mạch trong vòng lặp thứ hai, nếu counttrở thành âm, đơn giản hóa thân vòng lặp thành if(!counts.containsKey(item) || --counts.get(item).count < 0) return false;Ngoài ra, vòng lặp thứ 3 có thể được đơn giản hóa thànhfor(Count c: counts.values()) if(c.count != 0) return false;
Holger

@Holger Tôi đã xem xét một cái gì đó giống với cái đầu tiên (loại bỏ số đếm khi nó về 0, sẽ có tác dụng tương tự nhưng cũng biến các kiểm tra ở cuối thành "trả lại cho dù countscó trống"), nhưng không muốn làm mờ điểm chính: sử dụng bản đồ về cơ bản biến vấn đề này thành vấn đề O (N + M) và là mức tăng lớn nhất mà bạn có thể nhận được.
cHao

@cHao có, bạn xứng đáng với các khoản tín dụng để chỉ ra một giải pháp có độ phức tạp thời gian tốt hơn so với các giải pháp trước đó. Tôi chỉ tình cờ nghĩ về nó, bởi vì có một câu hỏi tương tự gần đây liên quan đến iterables. Vì hiện tại chúng tôi cũng có Java 8, nên đáng suy nghĩ lại về nó. Nếu bạn đoản mạch trong vòng lặp thứ hai khi số trở nên âm, thì vòng thứ ba trở nên lỗi thời. Hơn nữa, tránh đấm bốc có thể là con dao hai lưỡi, với Map.mergeviệc sử dụng số nguyên đóng hộp mới có thể đơn giản và hiệu quả hơn cho hầu hết các trường hợp sử dụng. Xem thêm câu trả lời này
Holger

10

Tôi muốn nói những câu trả lời này bỏ lỡ một mẹo.

Bloch, trong Java hiệu quả , thiết yếu, tuyệt vời, ngắn gọn của mình , nói, trong mục 47, tiêu đề "Biết và sử dụng các thư viện", "Để tóm tắt, đừng phát minh lại bánh xe". Và ông đưa ra một số lý do rất rõ ràng tại sao không.

Có một vài câu trả lời ở đây gợi ý các phương thức CollectionUtilstrong thư viện Bộ sưu tập Apache Commons nhưng không có câu trả lời nào phát hiện ra cách trả lời đẹp nhất, thanh lịch nhất cho câu hỏi này :

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

}

Thủ phạm : tức là các yếu tố không phổ biến cho cả hai Lists. Xác định thủ phạm thuộc về ai list1list2tương đối đơn giản bằng cách sử dụng CollectionUtils.intersection( list1, culprits )CollectionUtils.intersection( list2, culprits ) .
Tuy nhiên, nó có xu hướng sụp đổ trong các trường hợp như {"a", "a", "b"} disjunctionvới {"a", "b", "b"} ... ngoại trừ điều này không phải là lỗi của phần mềm, nhưng vốn có bản chất của sự tinh tế / mơ hồ của nhiệm vụ mong muốn.

Bạn luôn có thể kiểm tra mã nguồn (l. 287) cho một nhiệm vụ như thế này, do các kỹ sư Apache sản xuất. Một lợi ích của việc sử dụng mã của họ là nó sẽ được thử nghiệm và kiểm tra kỹ lưỡng, với nhiều trường hợp cạnh và các vấn đề được dự đoán và xử lý. Bạn có thể sao chép và điều chỉnh mã này vào nội dung trái tim của bạn nếu cần.


NB Lúc đầu tôi thất vọng vì không có CollectionUtilsphương pháp nào cung cấp phiên bản quá tải cho phép bạn áp đặt chính mình Comparator(vì vậy bạn có thể xác định lạiequals cho phù hợp với mục đích của mình).

Nhưng từ bộ sưu tập4 4.0, có một lớp mới, Equator"xác định sự bình đẳng giữa các đối tượng loại T". Khi kiểm tra mã nguồn của bộ sưu tập4 CollectionUtils.java dường như họ đang sử dụng phương thức này với một số phương thức, nhưng theo như tôi có thể thấy thì điều này không thể áp dụng cho các phương thức ở đầu tệp, sử dụng CardinalityHelperlớp ... bao gồm disjunctionintersection.

Tôi đoán rằng người Apache chưa hiểu về điều này bởi vì nó không tầm thường: bạn sẽ phải tạo ra một thứ như lớp "AbstractEquatingCollection", thay vì sử dụng các phần tử vốn có của nó equalshashCodecác phương thức thay vào đó sẽ phải sử dụng các phương thức đó của Equatorcho tất cả các phương pháp cơ bản, chẳng hạn như add, containsvv NB trên thực tế khi bạn nhìn vào mã nguồn, AbstractCollectionkhông thực hiện add, cũng không phân lớp trừu tượng của nó như AbstractSet... bạn phải đợi cho đến khi lớp bê tông như HashSetArrayListtrước addđược thực thi. Khá đau đầu.

Trong thời gian đó xem không gian này, tôi cho rằng. Giải pháp tạm thời rõ ràng sẽ là bọc tất cả các thành phần của bạn trong một lớp bao bọc bespoke sử dụng equalshashCodethực hiện loại đẳng thức bạn muốn ... sau đó thao tác Collectionsvới các đối tượng trình bao bọc này.


Ngoài ra, một người khôn ngoan đã nói "Biết chi phí của sự phụ thuộc"
Stanislaw Baranski

@StanislawBaranski Đó là một nhận xét thú vị. Có phải đó là một gợi ý rằng người ta không nên quá phụ thuộc vào các thư viện như vậy? Khi bạn sử dụng HĐH trên máy tính, đó là một bước nhảy vọt về niềm tin phải không? Lý do tôi rất vui khi sử dụng các thư viện Apache là vì tôi thực sự coi chúng có chất lượng rất cao và cho rằng các phương thức của chúng tuân thủ "hợp đồng" của chúng và đã được kiểm tra kỹ lưỡng. Bạn sẽ mất bao nhiêu thời gian để phát triển mã của riêng mình mà bạn tin tưởng hơn? Sao chép mã từ các thư viện Apache nguồn mở và xem xét kỹ lưỡng nó có thể là điều cần suy nghĩ về ...
loài gặm nhấm

8

Nếu tính chính xác của các mặt hàng không thành vấn đề (nghĩa là: các yếu tố lặp lại được coi là một), thì có một cách để làm điều này mà không phải sắp xếp:

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

Điều này sẽ tạo ra một Setra của mỗi List, và sau đó sử dụng HashSetcủa equalsphương pháp đó (tất nhiên) không quan tâm đến đặt hàng.

Nếu vấn đề về tim mạch, thì bạn phải giới hạn bản thân trong các cơ sở được cung cấp bởi List; Câu trả lời của @ jschoen sẽ phù hợp hơn trong trường hợp đó.


nếu danh sáchA = [a, b, c, c] và listB = [a, b, c]. kết quả sẽ đúng, nhưng danh sách không bằng nhau.
Nikolas

6

Chuyển đổi danh sách sang Multiset của Guava hoạt động rất tốt. Chúng được so sánh bất kể thứ tự của chúng và các yếu tố trùng lặp cũng được tính đến.

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

Điều này dựa trên giải pháp @cHao. Tôi bao gồm một số bản sửa lỗi và cải thiện hiệu suất. Điều này chạy nhanh gấp đôi so với giải pháp sao chép theo thứ tự. Hoạt động cho bất kỳ loại bộ sưu tập. Bộ sưu tập rỗng và null được coi là bằng nhau. Sử dụng để lợi thế của bạn;)

/**
 * 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;
}

Bạn có thể bỏ qua vòng lặp for cuối cùng bằng cách sử dụng bộ đếm tổng. Bộ đếm tổng sẽ đếm tổng số đếm ở mỗi giai đoạn. Tăng bộ đếm tổng trong vòng lặp for đầu tiên và giảm nó trong vòng lặp for thứ hai. Nếu bộ đếm tổng lớn hơn 0, các danh sách không khớp, nếu không thì chúng sẽ làm. Hiện tại, trong vòng lặp for cuối cùng, bạn kiểm tra xem tất cả các số có bằng không hay nói cách khác, nếu tổng của tất cả các số là 0. Sử dụng loại bộ đếm tổng đảo ngược kiểm tra này, trả về giá trị true nếu tổng số đếm bằng 0 hoặc sai.
SatA

IMO, đáng bỏ qua vòng lặp for đó vì khi danh sách khớp với nhau (trường hợp xấu nhất), vòng lặp for thêm một O (n) không cần thiết khác.
SatA

@SatA thực sự, bạn có thể loại bỏ vòng lặp thứ 3 mà không cần thay thế. Vòng lặp thứ hai đã trở lại falsekhi một khóa không tồn tại hoặc số của nó trở nên âm. Vì tổng kích thước của cả hai danh sách khớp nhau (điều này đã được kiểm tra trước), không thể có các giá trị khác không sau vòng lặp thứ hai, vì không thể có các giá trị dương cho một khóa mà không có giá trị âm cho một khóa khác.
Holger

@holger có vẻ như bạn hoàn toàn chính xác. Theo như tôi có thể nói, vòng 3 không cần thiết chút nào.
SatA

@SatAvới và với Java 8, điều này có thể được thực hiện chính xác, như trong câu trả lời này .
Holger

5

Hãy nghĩ làm thế nào bạn sẽ tự làm điều này, vắng mặt một máy tính hoặc ngôn ngữ lập trình. Tôi cung cấp cho bạn hai danh sách các yếu tố và bạn phải cho tôi biết nếu chúng có chứa các yếu tố giống nhau. Bạn sẽ làm điều này như thế nào?

Một cách tiếp cận, như đã đề cập ở trên, là sắp xếp các danh sách và sau đó đi từng yếu tố để xem chúng có bằng nhau không (đó là những gì List.equals ). Điều này có nghĩa là bạn được phép sửa đổi danh sách hoặc bạn được phép sao chép chúng - và không cần biết bài tập, tôi không thể biết liệu một trong hai hoặc cả hai đều được cho phép.

Một cách tiếp cận khác là đi qua từng danh sách, đếm xem mỗi yếu tố xuất hiện bao nhiêu lần. Nếu cả hai danh sách có cùng số đếm ở cuối, chúng có cùng các yếu tố. Mã cho điều đó sẽ là dịch từng danh sách sang một bản đồ elem -> (# of times the elem appears in the list)và sau đó gọi equalshai bản đồ. Nếu các bản đồ là HashMap, mỗi bản dịch đó là một hoạt động O (N), như là sự so sánh. Điều đó sẽ cung cấp cho bạn một thuật toán khá hiệu quả về mặt thời gian, với chi phí của một số bộ nhớ bổ sung.


5

Tôi đã có cùng một vấn đề và đưa ra một giải pháp khác. Điều này cũng hoạt động khi các bản sao có liên quan:

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;
}

Ưu điểm so với một số giải pháp khác:

  • độ phức tạp nhỏ hơn O (N²) (mặc dù tôi chưa kiểm tra hiệu năng thực sự của nó so với các giải pháp trong các câu trả lời khác ở đây);
  • xuất cảnh sớm;
  • kiểm tra null;
  • hoạt động ngay cả khi các bản sao có liên quan: nếu bạn có một mảng [1,2,3,3]và một mảng khác, [1,2,2,3]hầu hết các giải pháp ở đây cho bạn biết chúng giống nhau khi không xem xét thứ tự. Giải pháp này tránh điều này bằng cách loại bỏ các yếu tố bằng nhau khỏi danh sách tạm thời;
  • sử dụng đẳng thức ngữ nghĩa ( equals) và không tham chiếu đẳng thức ( ==);
  • không sắp xếp itens, vì vậy chúng không cần phải được sắp xếp (bởi implement Comparable) để giải pháp này hoạt động.

3

Nếu bạn không hy vọng sắp xếp các bộ sưu tập và bạn cần kết quả rằng ["A" "B" "C"] không bằng ["B" "B" "A" "C"],

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

là không đủ, bạn cũng cần phải kiểm tra kích thước:

    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

Giải pháp tận dụng phương pháp trừ 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

Nếu bạn quan tâm đến thứ tự, thì chỉ cần sử dụng phương thức bằng:

list1.equals(list2)

Nếu bạn không quan tâm đặt hàng thì hãy sử dụng

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

4
Anh ấy nói anh ấy không quan tâm đến trật tự.
mike gặm nhấm

0

Tốt nhất của cả hai thế giới [@DiddiZ, @Chalkos]: cái này chủ yếu dựa trên phương pháp @Chalkos, nhưng sửa một lỗi (ifst.next ()) và cải thiện kiểm tra ban đầu (lấy từ @DiddiZ) cũng như loại bỏ nhu cầu sao chép bộ sưu tập đầu tiên (chỉ cần loại bỏ các mục từ một bản sao của bộ sưu tập thứ hai).

Không yêu cầu chức năng băm hoặc sắp xếp và cho phép tồn tại sớm trên sự không bình đẳng, đây là cách thực hiện hiệu quả nhất. Đó là trừ khi bạn có độ dài bộ sưu tập trong hàng ngàn hoặc nhiều hơn và chức năng băm rất đơn giản.

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;
}

Nếu tôi không nhầm, độ phức tạp của thuật toán này trong kịch bản trường hợp có giá trị (trong đó các danh sách bằng nhau nhưng được sắp xếp theo cách ngược lại) sẽ là O (N * N!).
SatA

Trên thực tế, nó sẽ là O (N * (N / 2)), vì với mỗi lần lặp, kích thước mảng sẽ giảm.
jazzgil

0

Đây là một cách khác để kiểm tra sự bằng nhau của danh sách mảng có thể chứa giá trị 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);
}

Điểm của tất cả các bản sao này giữa danh sách và mảng là gì?
Holger

0

Giải pháp của tôi cho việc này. Nó không phải là quá mát mẻ, nhưng hoạt động tốt.

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();
}

-1

Trong trường hợp đó, danh sách {"a", "b"} và {"b", "a"} bằng nhau. Và {"a", "b"} và {"b", "a", "c"} không bằng nhau. Nếu bạn sử dụng danh sách các đối tượng phức tạp, hãy nhớ ghi đè phương thức bằng , vì chứa All sử dụng nó bên trong.

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

-1: đưa ra câu trả lời sai với {"a", "a", "b"} và {"a", "b", "b"}: kiểm tra mã nguồn cho AbstractCollection.containsAll(). Bạn phải cho phép có các yếu tố trùng lặp như chúng ta đang nói Listschứ không phải về Sets. Xin vui lòng xem câu trả lời của tôi.
mike gặm nhấm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.