Kiểm tra xem một danh sách có chứa phần tử từ danh sách kia không


105

Tôi có hai danh sách với các đối tượng khác nhau trong đó.

List<Object1> list1;
List<Object2> list2;

Tôi muốn kiểm tra xem phần tử từ list1 có tồn tại trong list2 hay không, dựa trên thuộc tính cụ thể (Đối tượng1 và Đối tượng2 có (trong số các đối tượng khác), một thuộc tính tương hỗ (với loại Long), có tên là Tên thuộc tính).

ngay bây giờ, tôi làm như thế này:

boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           //also do something
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

Nhưng tôi nghĩ rằng có một cách tốt hơn và nhanh hơn để làm điều này :) Ai đó có thể đề xuất nó không?

Cảm ơn!


đầu tiên, khi bạn đặt found = true; sau đó chỉ cần phá vỡ; hoặc đi ra khỏi vòng lặp
jsist

stackoverflow.com/questions/5187888/… . Hơn nữa, để tìm kiếm nhanh chóng, hãy thử sử dụng Tìm kiếm nhị phân và thay đổi DS của bạn để phù hợp với tình hình ...
jsist

họ có chung cha mẹ ngoài Object không?
Woot4Moo

@ Woot4Moo không, họ không
Ned

Câu trả lời:


219

Nếu bạn chỉ cần kiểm tra tính bình đẳng cơ bản, điều này có thể được thực hiện với JDK cơ bản mà không cần sửa đổi danh sách đầu vào trong một dòng

!Collections.disjoint(list1, list2);

Nếu bạn cần kiểm tra một thuộc tính cụ thể, điều đó khó hơn. Tôi muốn giới thiệu, theo mặc định,

list1.stream()
   .map(Object1::getProperty)
   .anyMatch(
     list2.stream()
       .map(Object2::getProperty)
       .collect(toSet())
       ::contains)

... thu thập các giá trị riêng biệt list2và kiểm tra từng giá trị list1để tìm sự hiện diện.


1
Điều này sẽ không luôn trả về false vì cả hai đều là 2 đối tượng khác nhau?
Venki

2
À, không? Kiểm tra rời rạc nếu không có đối tượng nào bằng () với nhau giữa hai tập hợp.
Louis Wasserman

13
Ngoài ra, xin lưu ý rằng, đối với danh sách, đây sẽ là O (n * m); nếu bạn sẵn sàng sao chép list1vào a Settrước khi so sánh, bạn sẽ nhận được O (n) + O (m), nghĩa là, O (n + m), với chi phí là một số RAM bổ sung; đó là vấn đề lựa chọn giữa tốc độ hoặc bộ nhớ.
Haroldo_OK

Điều này sẽ chỉ hoạt động nếu "Danh sách <Người> list1; Danh sách <Người> list2" nhưng không hoạt động trên hai đối tượng hoặc kiểu dữ liệu khác nhau như Danh sách <Người> list1; Liệt kê danh sách <Nhân viên> 2.
whoami

Tất nhiên, điều này sẽ không hoạt động đối với những trường hợp đó @Zephyr, đối với câu hỏi được đặt ra, nó hoạt động hoàn hảo miễn là bạn đã triển khai đúng bằng. đó là tất cả các vấn đề!
Syed Siraj Uddin

38

Bạn có thể sử dụng Apache Commons CollectionUtils :

if(CollectionUtils.containsAny(list1,list2)) {  
    // do whatever you want
} else { 
    // do other thing 
}  

Điều này giả định rằng bạn đã quá tải đúng chức năng bằng cho các đối tượng tùy chỉnh của mình.


9
nó đã được 4 năm và tôi cũng gọi rõ ràng gói và chức năng.
Woot4Moo

1
Downvote cho apache commons khi có một jdk chỉ giải pháp
ohcibi

9
@ohcibi Java cũng có trình ghi nhật ký tích hợp sẵn, bạn nên phản đối những người đề xuất sử dụng Log4j và Log4j2 khi bạn đang sử dụng.
Woot4Moo

1
@ Woot4Moo tùy. Không có lý do gì để phản đối nếu có lý do để sử dụng Log4j để giải quyết vấn đề OP. Trong trường hợp này, các dấu phẩy của apache sẽ đơn giản là vô dụng như trong 99% các câu trả lời đề xuất dấu phẩy apache.
ohcibi

1
@ohcibi nhưng nếu bạn đã sử dụng Apache commons thì nó không thực sự cồng kềnh. Đây là một câu trả lời tốt.
vab2048

19

Để rút ngắn logic của Narendra, bạn có thể sử dụng:

boolean var = lis1.stream().anyMatch(element -> list2.contains(element));

3
câu trả lời này được đánh giá thấp.
Kervvv

Bạn có thể rút ngắn hơn một chút nếu muốn:list1.stream().anyMatch(list2::contains);
tarka

9

một phương pháp của Collectiontên retainAllnhưng có một số tác dụng phụ cho bạn tham khảo

Chỉ giữ lại các phần tử trong danh sách này có trong bộ sưu tập được chỉ định (thao tác tùy chọn). Nói cách khác, xóa khỏi danh sách này tất cả các phần tử không có trong bộ sưu tập được chỉ định.

true nếu danh sách này thay đổi do cuộc gọi

Nó giống như

boolean b = list1.retainAll(list2);

5

Câu trả lời Loius là đúng, tôi chỉ muốn thêm một ví dụ:

listOne.add("A");
listOne.add("B");
listOne.add("C");

listTwo.add("D");
listTwo.add("E");
listTwo.add("F");      

boolean noElementsInCommon = Collections.disjoint(listOne, listTwo); // true

1
Tôi nghĩ nếu bạn thêm phần tử 'A' vào danh sách thứ hai listTwo.add ("A"); mặc dù Collections.disjoint (listOne, listTwo); trả về true.
Sairam Kukadala

2

cách nhanh hơn sẽ yêu cầu không gian bổ sung.

Ví dụ:

  1. đặt tất cả các mục trong một danh sách vào một HashSet (bạn phải tự mình triển khai hàm băm để sử dụng object.getAttributeSame ())

  2. Đi qua danh sách khác và kiểm tra xem có mục nào trong HashSet không.

Theo cách này, mỗi đối tượng được truy cập nhiều nhất một lần. và HashSet đủ nhanh để kiểm tra hoặc chèn bất kỳ đối tượng nào vào O (1).


2

Theo JavaDoc cho .contains(Object obj):

Trả về true nếu danh sách này chứa phần tử được chỉ định. Chính thức hơn, trả về true nếu và chỉ khi danh sách này chứa ít nhất một phần tử e sao cho (o == null? E == null: o.equals (e)).

Vì vậy, nếu bạn ghi đè .equals()phương thức của mình cho đối tượng đã cho, bạn sẽ có thể thực hiện:if(list1.contains(object2))...

Nếu các phần tử là duy nhất (tức là có các thuộc tính khác nhau), bạn có thể ghi đè .equals().hashcode()và lưu trữ mọi thứ trong đó HashSets. Điều này sẽ cho phép bạn kiểm tra xem một phần tử có chứa phần tử khác trong thời gian không đổi.


2

để làm cho nó nhanh hơn, bạn có thể thêm một khoảng nghỉ; theo cách đó, vòng lặp sẽ dừng lại nếu tìm thấy được đặt thành true:

boolean found = false;
for(Object1 object1 : list1){
   for(Object2 object2: list2){
       if(object1.getAttributeSame() == object2.getAttributeSame()){
           found = true;
           //also do something  
           break;
       }
    }
    if(!found){
        //do something
    }
    found = false;
}

Nếu bạn muốn có các bản đồ thay vì danh sách với các khóa thuộc tính tên, bạn có thể kiểm tra nhanh hơn một giá trị trong một bản đồ nếu có giá trị tương ứng trong bản đồ thứ hai hay không.


Chào Tom, cảm ơn vì đã chú ý! Có, tôi đã quên "break" trong khi nhập. Nhưng tôi đang nghĩ có lẽ có một số thuật toán, hoặc tôi nên thay đổi các danh sách này thành một số bộ sưu tập khác.
Ned

không có gì tốt hơn O (n * m)?
Woot4Moo

.getAttributeSame ()?
Maveň ツ

Việc triển khai cho phương thức getAttributeSame () từ Object1 và Object2 không được cung cấp, nhưng cũng không liên quan đến câu hỏi và câu trả lời; nó chỉ trả về một thuộc tính (Tên thuộc tính, một Long) mà cả hai classs đều có.
Tom

0

Bạn có thể xác định loại dữ liệu bạn nắm giữ không? nó có phải là dữ liệu lớn không? nó được sắp xếp? Tôi nghĩ rằng bạn cần xem xét các cách tiếp cận hiệu quả khác nhau tùy thuộc vào dữ liệu.

Ví dụ: nếu dữ liệu của bạn lớn và chưa được sắp xếp, bạn có thể thử lặp lại hai danh sách với nhau theo chỉ mục và lưu trữ từng thuộc tính danh sách trong một trình trợ giúp danh sách khác. thì bạn có thể kiểm tra chéo các thuộc tính hiện tại trong danh sách trợ giúp.

chúc may mắn

đã chỉnh sửa: và tôi không khuyên bạn nên nạp quá tải bằng. nó nguy hiểm và có thể chống lại ý nghĩa đối tượng của bạn.



0

Với java 8, chúng ta có thể làm như dưới đây để kiểm tra xem một danh sách có chứa bất kỳ phần tử nào của danh sách khác không

boolean var = lis1.stream().filter(element -> list2.contains(element)).findFirst().isPresent();

0

Nếu bạn muốn kiểm tra xem một phần tử có tồn tại trong danh sách hay không, hãy sử dụng phương thức chứa.

if (list1.contains(Object o))
{
   //do this
}
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.