Перевірте, чи містить один список елемент іншого


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

Але я думаю, що є кращий і швидший спосіб зробити це :) Чи може хтось запропонувати це?

Дякую!


по-перше, коли ви встановлюєте знайдено = true; потім просто зламати; або вийти з циклу
jsist

stackoverflow.com/questions/5187888/… . Більше того, для швидкого пошуку спробуйте скористатися Бінарним пошуком та змініть свій DS відповідно до ситуації ...
jsist

вони поділяють спільного батька крім Object?
Woot4Moo

@ Woot4Moo ні, вони не
Неділя

Відповіді:


220

Якщо вам просто потрібно перевірити базову рівність, це можна зробити з базовим JDK без зміни списків введення в одному рядку

!Collections.disjoint(list1, list2);

Якщо вам потрібно перевірити певну властивість, це складніше. Я б рекомендував, за замовчуванням,

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

... який збирає різні значення в list2і перевіряє кожне значення list1на наявність.


1
Невже це не завжди повернеться помилковим, оскільки обидва - це два різних об’єкти?
Венкі

2
Гм, ні? Тести нерозбірливості, якщо між двома колекціями немає об'єктів, рівних один одному ().
Луї Вассерман

13
Також зверніть увагу, що для списків це буде O (n * m); якщо ви готові скопіювати list1в a, Setперш ніж порівнювати, ви отримаєте O (n) + O (m), тобто O (n + m), ціною якоїсь додаткової оперативної пам’яті; це питання вибору між швидкістю чи пам’яттю.
Haroldo_OK

Це буде працювати лише в тому випадку, якщо "Список <Персона> список1; Список <Персона> список2", але не на двох різних об'єктах або типах даних, таких як Список <Персона> список1; Список <E Employee> list2.
whoami

Звичайно, це не спрацює для тих сценаріїв @Zephyr. На запитання, воно працює ідеально до тих пір, поки у вас будуть реалізовані правильні рівні. це все має значення!
Syed Siraj

38

Ви можете використовувати колекцію Apache Commons CollectionUtils :

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

Це передбачає, що ви належним чином перевантажили функціонал, рівний для власних об'єктів.


9
минуло 4 роки, і я також чітко закликаю пакет та функції.
Woot4Moo

1
Downvote для apache commons, коли є лише рішення jdk
ohcibi

9
@ohcibi У Java також є вбудований реєстратор, ви повинні перейти до людей, які пропонують використовувати Log4j та Log4j2, поки ви перебуваєте на ній.
Woot4Moo

1
@ Woot4Moo це залежить. Немає підстав зволікати, якщо є причина використовувати Log4j для вирішення проблеми ОП. У такому випадку апачі-общини були б просто марними, як у 99% відповідей, які пропонують апаші-общини.
ohcibi

1
@ohcibi, але якщо ви вже використовуєте спільноти Apache, це насправді не процвітає. Це була гарна відповідь.
vab2048

20

Щоб скоротити логіку Нарендри, ви можете скористатися цим:

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

3
ця відповідь недооцінена.
Кервв

1
Ви можете трохи скоротити його, якщо хочете:list1.stream().anyMatch(list2::contains);
тарка

9

Існує один метод з Collectionімені , retainAllале мають деякі побічні ефекти для вас еталонних

Зберігає лише елементи цього списку, які містяться у зазначеній колекції (необов'язкова операція). Іншими словами, видаляє зі цього списку всі його елементи, які не містяться у зазначеній колекції.

вірно, якщо цей список змінився в результаті дзвінка

Це як

boolean b = list1.retainAll(list2);

5

Відповідь Лоя правильна, я просто хочу додати приклад:

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); повертає правду.
Сайрам Кукадала

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

щоб зробити це швидше, можна додати перерву; таким чином цикл зупиниться, якщо для параметра знаходження встановлено значення 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;
}

Якщо ви матимете карти замість списків із клавішами attributeSame, ви можете швидше перевірити значення на одній карті, чи є відповідне значення у другій карті чи ні.


Привіт Том, дякую, що помітили Так, я забув "зламати" під час набору тексту. Але я думав, можливо, існує якийсь алгоритм, або я повинен змінити ці списки в якісь інші колекції.
Неділя

хіба немає нічого кращого, ніж O (n * m)?
Woot4Moo

.getAttributeSame ()?
Maveň ツ

Реалізація методу getAttributeSame () від Object1 та Object2 не надається, але також не стосується питання та відповіді; він просто повертає атрибут (attributeSame, Long), який мають обидва класи.
Том

0

Чи можете ви визначити тип даних, які ви зберігаєте? це великі дані? це сортується? Я думаю, що вам потрібно враховувати різні підходи до ефективності залежно від даних.

Наприклад, якщо ваші дані великі і несортовані, ви можете спробувати ітерапіювати два списки разом за індексом та зберігати кожен атрибут списку в іншому помічнику списку. тоді ви можете перехрестити перевірку за поточними атрибутами у списках помічників.

Щасти

відредаговано: і я б не рекомендував перевантажувати рівних. це небезпечно і, ймовірно, проти вашого значення об'єкта oop



0

З java 8, ми можемо зробити , як показано нижче , щоб перевірити , якщо один список містить будь - який елемент іншого списку

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

0

Якщо ви хочете перевірити, чи існує елемент у списку, використовуйте метод містить.

if (list1.contains(Object o))
{
   //do this
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.