ตรวจสอบว่ารายการหนึ่งมีองค์ประกอบจากอีกรายการหนึ่งหรือไม่


105

ฉันมีสองรายการที่มีวัตถุต่างกัน

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

ฉันต้องการตรวจสอบว่าองค์ประกอบจาก list1 มีอยู่ใน list2 หรือไม่โดยยึดตามแอตทริบิวต์เฉพาะ (Object1 และ Object2 มี (ในกลุ่มอื่น ๆ ) หนึ่งแอตทริบิวต์ร่วมกัน (ที่มีประเภท Long) ชื่อ attributeSame)

ตอนนี้ฉันทำแบบนี้:

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

แต่ฉันคิดว่ามีวิธีที่ดีกว่าและเร็วกว่านี้ :) มีใครเสนอได้ไหม

ขอบคุณ!


ประการแรกเมื่อคุณตั้งค่า found = true; จากนั้นก็ทำลาย; หรือออกจากวง
jsist

stackoverflow.com/questions/5187888/… . ยิ่งไปกว่านั้นสำหรับการค้นหาที่รวดเร็วให้ลองใช้ Binary Search และเปลี่ยน DS ของคุณเพื่อให้เข้ากับสถานการณ์ ...
jsist

พวกเขาแบ่งปันผู้ปกครองร่วมกันนอกเหนือจาก Object หรือไม่?
Woot4Moo

@ Woot4Moo ไม่พวกเขาไม่
เน็ด

คำตอบ:


223

หากคุณต้องการทดสอบความเท่าเทียมขั้นพื้นฐานคุณสามารถทำได้ด้วย JDK พื้นฐานโดยไม่ต้องแก้ไขรายการอินพุตในบรรทัดเดียว

!Collections.disjoint(list1, list2);

หากคุณต้องการทดสอบคุณสมบัติเฉพาะสิ่งนั้นยากกว่า ฉันอยากจะแนะนำโดยค่าเริ่มต้น

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

... ซึ่งรวบรวมค่าที่แตกต่างกันlist2และทดสอบแต่ละค่าlist1เพื่อแสดง


1
สิ่งนี้จะไม่ส่งคืนเท็จเสมอไปเนื่องจากทั้งสองเป็นวัตถุที่แตกต่างกัน 2 ชิ้นหรือไม่?
Venki

2
อืมไม่? การทดสอบไม่ปะติดปะต่อกันหากไม่มีวัตถุใดเท่ากับ () ซึ่งกันและกันระหว่างสองคอลเล็กชัน
Louis Wasserman

13
นอกจากนี้โปรดทราบว่าสำหรับรายการนี้จะเป็น O (n * m); หากคุณยินดีที่จะคัดลอกlist1ลงในSetก่อนทำการเปรียบเทียบคุณจะได้รับ O (n) + O (m) นั่นคือ O (n + m) ในราคาของ RAM เพิ่มเติม เป็นเรื่องของการเลือกระหว่างความเร็วหรือหน่วยความจำ
Haroldo_OK

สิ่งนี้จะใช้ได้เฉพาะในกรณีที่ "List <Person> list1; List <Person> list2" แต่ไม่ใช่บนวัตถุหรือประเภทข้อมูลที่แตกต่างกันสองรายการเช่น List <Person> list1; รายการ <Employee> list2.
whoami

แน่นอนว่าสิ่งนี้จะใช้ไม่ได้กับสถานการณ์เหล่านั้น @Zephyr สำหรับคำถามที่ถามมันจะทำงานได้อย่างสมบูรณ์แบบตราบเท่าที่คุณมีการใช้งานที่ถูกต้องเท่ากับ นั่นคือเรื่องทั้งหมด!
Syed Siraj Uddin

38

คุณสามารถใช้Apache Commons CollectionUtils :

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

สิ่งนี้จะถือว่าคุณได้โหลดฟังก์ชันการทำงานเท่ากับสำหรับอ็อบเจ็กต์แบบกำหนดเองของคุณมากเกินไป


9
เป็นเวลา 4 ปีแล้วและฉันยังเรียกแพ็คเกจและฟังก์ชันออกมาอย่างชัดเจน
Woot4Moo

1
downvote สำหรับคอมมอน Apache เมื่อมีการ jdk เพียงการแก้ปัญหา
ohcibi

9
@ohcibi Java ยังมีคนตัดไม้ในตัวคุณควรลงคะแนนคนที่แนะนำให้ใช้ Log4j และ Log4j2 ในขณะที่คุณอยู่ที่นั่น
Woot4Moo

1
@ Woot4Moo มันขึ้นอยู่กับ ไม่มีเหตุผลที่จะลงคะแนนหากมีเหตุผลที่จะใช้ Log4j เพื่อแก้ปัญหา OPs ในกรณีนี้ apache commons ก็จะไม่มีประโยชน์เหมือนในคำตอบ 99% ที่แนะนำ apache commons
ohcibi

1
@ohcibi แต่ถ้าคุณใช้ Apache commons อยู่แล้วมันจะไม่บวมจริงๆ นี่เป็นคำตอบที่ดี
vab2048

20

เพื่อให้ตรรกะของ Narendra สั้นลงคุณสามารถใช้สิ่งนี้:

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

3
คำตอบนี้ไม่ได้รับการชื่นชม
Kervvv

1
คุณสามารถย่อให้สั้นลงได้อีกเล็กน้อยหากต้องการ:list1.stream().anyMatch(list2::contains);
tarka

9

นอกจากนี้วิธีการหนึ่งของCollectionการตั้งชื่อretainAllแต่มีบางส่วนผลข้างเคียงสำหรับคุณอ้างอิง

เก็บเฉพาะองค์ประกอบในรายการนี้ที่มีอยู่ในคอลเล็กชันที่ระบุ (การดำเนินการทางเลือก) กล่าวอีกนัยหนึ่งคือลบองค์ประกอบทั้งหมดที่ไม่มีอยู่ในคอลเล็กชันที่ระบุออกจากรายการนี้

เป็นจริงหากรายการนี้เปลี่ยนแปลงอันเป็นผลมาจากการโทร

มันเหมือนกับ

boolean b = list1.retainAll(list2);

5

คำตอบของ Loius ถูกต้องฉันแค่อยากจะเพิ่มตัวอย่าง:

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
ฉันคิดว่าถ้าคุณเพิ่มองค์ประกอบ 'A' ในรายการที่สอง listTwo.add ("A"); แม้ว่า Collections.disjoint (listOne, listTwo); คืนค่าจริง
Sairam Kukadala

2

วิธีที่เร็วกว่าจะต้องใช้พื้นที่เพิ่มเติม

ตัวอย่างเช่น:

  1. ใส่รายการทั้งหมดในรายการเดียวลงใน HashSet (คุณต้องใช้ฟังก์ชันแฮชด้วยตัวเองเพื่อใช้ object.getAttributeSame ())

  2. ไปดูรายการอื่นและตรวจสอบว่ามีรายการใดอยู่ใน HashSet หรือไม่

ด้วยวิธีนี้จะมีการเยี่ยมชมวัตถุแต่ละชิ้นพร้อมกันมากที่สุด และ HashSet เร็วพอที่จะตรวจสอบหรือแทรกวัตถุใด ๆ ใน O (1)


2

ตาม JavaDoc สำหรับ.contains(Object obj):

ส่งคืนจริงหากรายการนี้มีองค์ประกอบที่ระบุ อย่างเป็นทางการมากขึ้นจะคืนค่าจริงถ้ารายการนี้มีอย่างน้อยหนึ่งองค์ประกอบ e เช่นนั้น (o == null? e == null: o.equals (e))

ดังนั้นหากคุณแทนที่.equals()วิธีการของคุณสำหรับวัตถุที่คุณกำหนดคุณควรจะทำได้:if(list1.contains(object2))...

ถ้าองค์ประกอบจะไม่ซ้ำกัน (เช่น. มีแอตทริบิวต์ที่แตกต่างกัน) คุณสามารถแทนที่.equals()และและทุกอย่างในร้าน.hashcode() HashSetsสิ่งนี้จะช่วยให้คุณตรวจสอบว่ามีองค์ประกอบอื่นในเวลาคงที่หรือไม่


2

เพื่อให้เร็วขึ้นคุณสามารถเพิ่มช่วงพักได้ วิธีนั้นลูปจะหยุดหากพบว่าตั้งค่าเป็นจริง:

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

หากคุณมีแผนที่แทนรายการที่มีเป็นคีย์ attributeSame คุณสามารถตรวจสอบค่าในแผนที่เดียวได้เร็วขึ้นว่ามีค่าที่ตรงกันในแผนที่ที่สองหรือไม่


สวัสดีทอมขอบคุณที่สังเกตเห็น! ใช่ฉันลืม "หยุดพัก" ขณะพิมพ์ แต่ฉันคิดว่าอาจมีอัลกอริทึมบางอย่างหรือฉันควรเปลี่ยนรายการเหล่านี้เป็นคอลเล็กชันอื่น
เนด

ไม่มีอะไรดีไปกว่า O (n * m)?
Woot4Moo

.getAttributeSame ()?
Maveňツ

ไม่มีการใช้งานเมธอด getAttributeSame () จาก Object1 และ Object2 แต่ยังไม่เกี่ยวข้องกับคำถามและคำตอบ เพียงส่งคืนแอตทริบิวต์ (attributeSame, a Long) ซึ่งทั้งสองคลาสมี
ทอม

0

คุณสามารถกำหนดประเภทของข้อมูลที่คุณเก็บไว้ได้หรือไม่? เป็นข้อมูลขนาดใหญ่หรือไม่ จัดเรียงหรือเปล่า ฉันคิดว่าคุณต้องพิจารณาแนวทางประสิทธิภาพที่แตกต่างกันขึ้นอยู่กับข้อมูล

ตัวอย่างเช่นหากข้อมูลของคุณมีขนาดใหญ่และไม่ได้รับการจัดเรียงคุณสามารถลองทำซ้ำทั้งสองรายการพร้อมกันด้วยดัชนีและจัดเก็บแอตทริบิวต์รายการแต่ละรายการไว้ในตัวช่วยรายการอื่น จากนั้นคุณสามารถตรวจสอบข้ามโดยแอตทริบิวต์ปัจจุบันในรายการตัวช่วย

โชคดี

แก้ไข: และฉันไม่แนะนำให้ใช้การโอเวอร์โหลดเท่ากับ มันอันตรายและอาจต่อต้านความหมายของวัตถุของคุณ



0

ด้วยjava 8เราสามารถทำดังนี้เพื่อตรวจสอบว่ารายการหนึ่งมีองค์ประกอบของรายการอื่นหรือไม่

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

0

หากคุณต้องการตรวจสอบว่ามีองค์ประกอบอยู่ในรายการหรือไม่ให้ใช้วิธีการมี

if (list1.contains(Object o))
{
   //do this
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.