Bir listenin diğerinden öğe içerip içermediğini kontrol edin


108

İçlerinde farklı nesneler olan iki listem var.

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

List1'deki öğenin list2'de belirli özniteliğe (Object1 ve Object2 (diğerlerinin yanı sıra), bir karşılıklı özniteliğe (Long türüne sahip), attributeSame adında) bağlı olup olmadığını kontrol etmek istiyorum.

şu anda, bunu şöyle yapıyorum:

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

Ama bence bunu yapmanın daha iyi ve hızlı bir yolu var :) Biri bunu önerebilir mi?

Teşekkürler!


ilk olarak, found = true; sonra basitçe kırın; veya döngüden
çıkın

stackoverflow.com/questions/5187888/… . Ayrıca, hızlı arama için İkili Aramayı kullanmayı deneyin ve duruma uygun hale
getirmek için DS'nizi

Object dışında ortak bir ebeveyni paylaşıyorlar mı?
Woot4Moo

@ Woot4Moo hayır, onlar değil
Ned

Yanıtlar:


226

Yalnızca temel eşitliği test etmeniz gerekiyorsa, bu, tek satırdaki giriş listelerini değiştirmeden temel JDK ile yapılabilir.

!Collections.disjoint(list1, list2);

Belirli bir mülkü test etmeniz gerekiyorsa, bu daha zordur. Varsayılan olarak tavsiye ederim,

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

... içindeki farklı değerleri toplayan list2ve her bir değeri list1mevcudiyet için test eden .


1
Her ikisi de 2 farklı nesne olduğu için bu her zaman yanlış döndürmez mi?
Venki

2
Hayır? Ayrık, iki koleksiyon arasında birbirine eşit () nesneler olup olmadığını test eder.
Louis Wasserman

13
Ayrıca, listeler için bunun O (n * m) olacağını unutmayın. Karşılaştırmadan önce list1bir kopyalamaya istekli iseniz Set, fazladan RAM karşılığında O (n) + O (m), yani O (n + m) elde edersiniz; bu hız veya bellek arasında seçim yapma meselesidir.
Haroldo_OK

Bu yalnızca "List <Person> list1; List <Person> list2" ise çalışır, ancak List <Person> list1 gibi iki farklı nesne veya veri türünde çalışmaz; <Çalışan> listesi listesi 2.
whoami

Elbette bu, @Zephyr senaryoları için işe yaramayacak, sorulan soru için, sağ eşitler uygulandığı sürece mükemmel çalışıyor. önemli olan bu!
Syed Siraj Uddin

38

Apache Commons CollectionUtils'i kullanabilirsiniz :

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

Bu, özel nesneleriniz için eşittir işlevselliğini doğru şekilde aşırı yüklediğinizi varsayar.


9
4 yıl oldu ve ben de paketi ve işlevi açıkça belirtiyorum.
Woot4Moo

1
Yalnızca JDK için bir çözüm olduğunda apache commons için olumsuz oy verin
ohcibi

9
@ohcibi Java'da yerleşik bir kaydedici de vardır, siz oradayken Log4j ve Log4j2'yi kullanmayı öneren kişilere oy vermelisiniz.
Woot4Moo

1
@ Woot4Moo buna bağlıdır. OPs sorununu çözmek için Log4j kullanmak için bir neden varsa, olumsuz oy kullanmak için bir neden yoktur. Bu durumda apache commons, apache commons öneren yanıtların% 99'unda olduğu gibi, basitçe gereksiz bir şişkinlik olacaktır.
ohcibi

1
@ohcibi ama zaten Apache commons kullanıyorsanız, o zaman gerçekten şişkin değil. Bu iyi bir cevaptı.
vab2048

20

Narendra'nın mantığını kısaltmak için şunu kullanabilirsiniz:

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

3
bu cevap yeterince takdir edilmiyor.
Kervvv

1
İsterseniz biraz daha kısaltabilirsiniz:list1.stream().anyMatch(list2::contains);
tarka

9

Orada bir yöntem ait Collectionadlandırılmış retainAllancak bazı sahip yan etkileri sizin için referans

Yalnızca bu listedeki belirtilen koleksiyonda bulunan öğeleri tutar (isteğe bağlı işlem). Diğer bir deyişle, belirtilen koleksiyonda bulunmayan tüm öğelerini bu listeden kaldırır.

arama sonucunda bu liste değiştiyse doğrudur

Gibi

boolean b = list1.retainAll(list2);

5

Loius cevabı doğru, sadece bir örnek eklemek istiyorum:

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
ListTwo.add ("A") ikinci listeye 'A' öğesi eklerseniz; Collections.disjoint (listOne, listTwo) olsa bile; true döndürür.
Sairam Kukadala

2

daha hızlı yol ek alan gerektirecektir.

Örneğin:

  1. bir listedeki tüm öğeleri bir HashSet'e yerleştirin (object.getAttributeSame () kullanmak için hash işlevini kendiniz uygulamanız gerekir)

  2. Diğer listeye gidin ve HashSet'te herhangi bir öğe olup olmadığını kontrol edin.

Bu şekilde her nesne en fazla bir kez ziyaret edilir. ve HashSet, O (1) 'e herhangi bir nesneyi kontrol etmek veya eklemek için yeterince hızlıdır.


2

JavaDoc'a göre .contains(Object obj):

Bu liste belirtilen öğeyi içeriyorsa doğru döndürür. Daha resmi olarak, ancak ve ancak bu liste en az bir e öğesi içeriyorsa (o == null? E == null: o.equals (e)) doğru sonucunu döndürür.

Dolayısıyla .equals(), verilen nesne için yönteminizi geçersiz kılarsanız , şunları yapabilmelisiniz:if(list1.contains(object2))...

Öğeler benzersiz olacaksa (yani, farklı özniteliklere sahipse) .equals()ve .hashcode()ve her şeyi içinde saklayabilirsiniz HashSets. Bu, birinin sabit zamanda başka bir element içerip içermediğini kontrol etmenizi sağlar.


2

daha hızlı hale getirmek için bir ara ekleyebilirsiniz; bu şekilde bulunursa döngü durur: true değerine ayarlanır:

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

Eğer anahtar olarak attributeSame olan listeler yerine haritalarınız olsaydı, ikinci haritada karşılık gelen bir değer olup olmadığını bir haritada bir değeri daha hızlı kontrol edebilirsiniz.


Merhaba Tom, fark ettiğin için teşekkürler! Evet, yazarken "ara" yı unuttum. Ama düşünüyordum da belki bir algoritma var ya da bu listeleri başka koleksiyonlara dönüştürmeliyim.
Ned

O (n * m) den daha iyi bir şey yok mu?
Woot4Moo

.getAttributeSame ()?
Maveň ツ

Object1 ve Object2'den getAttributeSame () yönteminin uygulanması sağlanmaz, ancak soru ve yanıtla da alakalı değildir; sadece her iki sınıfın da sahip olduğu bir öznitelik (öznitelikAdı, bir Uzun) döndürür.
Tom

0

Tuttuğunuz verilerin türünü tanımlayabilir misiniz? büyük veri mi? sıralandı mı? Verilere bağlı olarak farklı verimlilik yaklaşımları düşünmeniz gerektiğini düşünüyorum.

Örneğin, verileriniz büyükse ve sıralanmamışsa, iki listeyi dizine göre birlikte yinelemeyi deneyebilir ve her liste özniteliğini başka bir liste yardımcısında depolayabilirsiniz. daha sonra yardımcı listelerdeki mevcut özniteliklere göre çapraz kontrol yapabilirsiniz.

iyi şanslar

düzenlendi: ve eşittir aşırı yüklemeyi önermem. tehlikeli ve muhtemelen nesnenize aykırı anlamı.



0

İle java 8, bir listenin başka bir listenin herhangi bir öğesini içerip içermediğini kontrol etmek için aşağıdaki gibi yapabiliriz

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

0

Listede bir eleman olup olmadığını kontrol etmek istiyorsanız, içerir yöntemini kullanın.

if (list1.contains(Object o))
{
   //do this
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.