Các yếu tố chung trong hai danh sách


94

Tôi có hai ArrayListđối tượng với ba số nguyên mỗi đối tượng. Tôi muốn tìm cách trả về các phần tử chung của hai danh sách. Có ai biết cách tôi có thể đạt được điều này không?

Câu trả lời:


160

Sử dụng Collection#retainAll().

listA.retainAll(listB);
// listA now contains only the elements which are also contained in listB.

Nếu bạn muốn tránh những thay đổi bị ảnh hưởng listA, thì bạn cần tạo một thay đổi mới.

List<Integer> common = new ArrayList<Integer>(listA);
common.retainAll(listB);
// common now contains only the elements which are contained in listA and listB.

RetainAll trả về một danh sách mới? Tôi đã cố gắng lưu trữ kết quả giữ lại vào một danh sách mới như tempList.addAll (listA.retainAll (listB)); nhưng nó không hoạt động
zenitis

1
Như đã trả lời trong liên kết phía sau Collection#retainAll()và các nhận xét trong các đoạn mã, không, nó không. Các thay đổi được phản ánh trong danh sách mà bạn đang gọi phương thức.
BalusC

Vấn đề là danh sách phổ biến được khởi tạo với kích thước 3, sau đó bạn cố gắng thay đổi kích thước của nó bằng cách chỉ trả về một hoặc hai phần tử. Tôi thử những gì bạn đề xuất và nó đưa tôi ra khỏi giới hạn ngoại lệ.
zenitis

Trong cách tiếp cận này, tôi sẽ không thể so khớp số lần xuất hiện của phần tử ....... ví dụ: listA {2,3,5} và listB {5 5}, nếu tôi thực hiện listB.retainAll (listA) , listB bây giờ sẽ có {5,5} ...... Tôi muốn kết quả cuối cùng của mình sau khi so sánh listA và listB là {5}. Vui lòng đề xuất cách chúng tôi có thể đạt được điều này
NANCY 22/09/15

1
Nếu được thực hiện với sự lựa chọn sai đối tượng sưu tập, nó có thể tạo ra một ngoại lệ không được hỗ trợ. Tất nhiên, ví dụ trên với ArrayList hoạt động.
demongolem

39

Bạn có thể sử dụng các thao tác đặt giao nhau với các ArrayListđối tượng của mình .

Một cái gì đó như thế này:

List<Integer> l1 = new ArrayList<Integer>();

l1.add(1);
l1.add(2);
l1.add(3);

List<Integer> l2= new ArrayList<Integer>();
l2.add(4);
l2.add(2);
l2.add(3);

System.out.println("l1 == "+l1);
System.out.println("l2 == "+l2);

List<Integer> l3 = new ArrayList<Integer>(l2);
l3.retainAll(l1);

    System.out.println("l3 == "+l3);

Bây giờ, l3chỉ nên có các phần tử chung giữa l1l2.

CONSOLE OUTPUT
l1 == [1, 2, 3]
l2 == [4, 2, 3]
l3 == [2, 3]

6
Lưu ý rằng theo cách này, các thay đổi cũng được phản ánh trong đó l2. Bạn có thể muốn nói List<Integer> l3 = new ArrayList<Integer>(l2);thay vào đó.
BalusC

Vấn đề sẽ phức tạp hơn một chút nếu giả sử l1 có 2 phần tử và l2 có 3 phần tử giống nhau. Trả về keepAll đặt 3 phần tử đó trong l3 mặc dù nó chỉ được chứa hai lần trong l1.
demongolem

35

Tại sao phải phát minh lại bánh xe? Sử dụng Bộ sưu tập Commons :

CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)

Đây là một giải pháp tuyệt vời, tuy nhiên như tôi đã đề cập ở trên, nó có hành vi khác với retainAll()các phần tử lặp lại. Vì vậy, khả năng một đúng và một sai tùy thuộc vào cách bạn tiếp cận vấn đề.
demongolem

17

Sử dụng Stream.filter()phương pháp của Java 8 kết hợp với List.contains():

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;

/* ... */

List<Integer> list1 = asList(1, 2, 3, 4, 5);
List<Integer> list2 = asList(1, 3, 5, 7, 9);

List<Integer> common = list1.stream().filter(list2::contains).collect(toList());

4
Chứa có vẻ như nó sẽ là một phép toán O (n), sẽ được gọi là n lần, trừ khi trình biên dịch thực hiện điều gì đó thông minh. Có ai biết liệu ở trên chạy trong thời gian tuyến tính hoặc bậc hai?
Regorsmitz

1
Nó sẽ là một phép toán * n!
Lakshmikant Deshpande

5

nhập mô tả hình ảnh ở đây

            List<String> lista =new ArrayList<String>();
            List<String> listb =new ArrayList<String>();

            lista.add("Isabella");
            lista.add("Angelina");
            lista.add("Pille");
            lista.add("Hazem");

            listb.add("Isabella");
            listb.add("Angelina");
            listb.add("Bianca");

            // Create an aplusb list which will contain both list (list1 and list2) in which common element will occur twice 
            List<String> listapluslistb =new ArrayList<String>(lista);    
            listapluslistb.addAll(listb);

            // Create an aunionb set which will contain both list (list1 and list2) in which common element will occur once
            Set<String> listaunionlistb =new HashSet<String>(lista);
            listaunionlistb.addAll(listb);

            for(String s:listaunionlistb)
            {
                listapluslistb.remove(s);
            }
            System.out.println(listapluslistb);

Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Michael Parker,

5
List<Integer> listA = new ArrayList<>();
    listA.add(1);
    listA.add(5);
    listA.add(3);
    listA.add(4);   

List<Integer> listB = new ArrayList<>();
    listB.add(1);
    listB.add(5);
    listB.add(6);
    listB.add(7);
System.out.println(listA.stream().filter(listB::contains).collect(Collectors.toList()));


Java 1.8 Stream API Solutions

Đầu ra [1, 5]


-Chúng ta có thể xác định danh sách là List <Integer> listA = asList (1, 5, 3, 4); List <Integer> listB = asList (1, 5, 6, 7);
Rajeev Ranjan

4

Bạn có thể lấy các phần tử chung giữa hai danh sách bằng cách sử dụng phương pháp "keepAll". Phương pháp này sẽ loại bỏ tất cả các phần tử không khớp khỏi danh sách mà nó áp dụng.

Ex.: list.retainAll(list1);

Trong trường hợp này khỏi danh sách, tất cả các phần tử không có trong list1 sẽ bị xóa và chỉ còn lại những phần tử phổ biến giữa list và list1.

List<Integer> list = new ArrayList<>();
list.add(10);
list.add(13);
list.add(12);
list.add(11);

List<Integer> list1 = new ArrayList<>();
list1.add(10);
list1.add(113);
list1.add(112);
list1.add(111);
//before retainAll
System.out.println(list);
System.out.println(list1);
//applying retainAll on list
list.retainAll(list1);
//After retainAll
System.out.println("list::"+list);
System.out.println("list1::"+list1);

Đầu ra:

[10, 13, 12, 11]
[10, 113, 112, 111]
list::[10]
list1::[10, 113, 112, 111]

LƯU Ý: Sau khi keepAll được áp dụng trên danh sách, danh sách chứa phần tử chung giữa list và list1.


4
public <T> List<T> getIntersectOfCollections(Collection<T> first, Collection<T> second) {
        return first.stream()
                .filter(second::contains)
                .collect(Collectors.toList());
    }

3
    // Create two collections:
    LinkedList<String> listA =  new LinkedList<String>();
    ArrayList<String> listB =  new ArrayList<String>();

    // Add some elements to listA:
    listA.add("A");
    listA.add("B");
    listA.add("C");
    listA.add("D");

    // Add some elements to listB:
    listB.add("A");
    listB.add("B");
    listB.add("C");

    // use 

    List<String> common = new ArrayList<String>(listA);
    // use common.retainAll

    common.retainAll(listB);

    System.out.println("The common collection is : " + common);

3

xem xét hai danh sách L1 ans L2

Sử dụng Java8, chúng ta có thể dễ dàng tìm ra

L1.stream().filter(L2::contains).collect(Collectors.toList())


1

Trong trường hợp bạn muốn tự làm ..

List<Integer> commons = new ArrayList<Integer>();

for (Integer igr : group1) {
    if (group2.contains(igr)) {
        commons.add(igr);
    }
}

System.out.println("Common elements are :: -");
for (Integer igr : commons) {
    System.out.println(" "+igr);
}

1
OP đã yêu cầu một cách để tìm ra những phần tử nào là chung chứ không phải có bao nhiêu phần tử chung.
Brendon Dugan

@BrendonDugan - Đó là những gì mã này làm. Danh sách commonschứa các yếu tố chung. Vòng lặp thứ hai in chúng trên bảng điều khiển. Tôi không thấy mã đang đếm các phần tử phổ biến ở đâu.
Ajoy Bhatia

@AjoyBhatia - Khi tôi đưa ra nhận xét của mình (vào năm 2013), mã chỉ trả về một số phần tử phổ biến.
Brendon Dugan

@BrendonDugan Ồ, được rồi. Xin lỗi vì điều đó. Tôi nên lưu ý rằng câu trả lời có thể được chỉnh sửa tại chỗ nhưng ý kiến thường còn sót lại như là, trong thứ tự thời gian :-)
Ajoy Bhatia

0

Một số câu trả lời ở trên tương tự nhưng không giống nhau vì vậy hãy đăng nó như một câu trả lời mới.

Giải pháp:
1. Sử dụng HashSet để giữ các phần tử cần được loại bỏ
2. Thêm tất cả các phần tử của list1 vào HashSet
3. lặp lại list2 và xóa các phần tử khỏi HashSet có trong list2 ==> có trong cả list1 và list2
4 . Bây giờ hãy lặp lại HashSet và xóa các phần tử khỏi list1 (vì chúng ta đã thêm tất cả các phần tử của list1 vào set), cuối cùng, list1 có tất cả các phần tử chung
Lưu ý: Chúng ta có thể thêm tất cả các phần tử của list2 và trong lần lặp thứ 3, chúng ta nên xóa các phần tử khỏi danh sách2.

Độ phức tạp về thời gian: O (n) Độ
phức tạp về không gian: O (n)

Mã:

import com.sun.tools.javac.util.Assert;
import org.apache.commons.collections4.CollectionUtils;

    List<Integer> list1 = new ArrayList<>();
    list1.add(1);
    list1.add(2);
    list1.add(3);
    list1.add(4);
    list1.add(5);

    List<Integer> list2 = new ArrayList<>();
    list2.add(1);
    list2.add(3);
    list2.add(5);
    list2.add(7);
    Set<Integer> toBeRemoveFromList1 = new HashSet<>(list1);
    System.out.println("list1:" + list1);
    System.out.println("list2:" + list2);
    for (Integer n : list2) {
        if (toBeRemoveFromList1.contains(n)) {
            toBeRemoveFromList1.remove(n);
        }
    }
    System.out.println("toBeRemoveFromList1:" + toBeRemoveFromList1);
    for (Integer n : toBeRemoveFromList1) {
        list1.remove(n);
    }
    System.out.println("list1:" + list1);
    System.out.println("collectionUtils:" + CollectionUtils.intersection(list1, list2));
    Assert.check(CollectionUtils.intersection(list1, list2).containsAll(list1));

đầu ra:

list1:[1, 2, 3, 4, 5]
list2:[1, 3, 5, 7]
toBeRemoveFromList1:[2, 4]
list1:[1, 3, 5]
collectionUtils:[1, 3, 5]
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.