Java seti için 'içerir' gibi bir şey?


307

Aynı türden iki setim var, A ve B.

A'nın B setinden herhangi bir eleman içerip içermediğini bulmalıyım.

Setler üzerinde tekrar etmeden bunu yapmanın en iyi yolu ne olurdu? Set kütüphanesi vardır contains(object)ve containsAll(collection)ancak containsAny(collection).


4
Verimlilik nedeniyle veya kod temizliği için yineleme yapmaktan kaçınıyor musunuz?
yshavit

Yanıtlar:


527

Çalışmaz mıydı Collections.disjoint(A, B)? Belgelerden:

Belirtilen trueiki koleksiyonun ortak öğesi yoksa döndürür .

Bu nedenle, falsekoleksiyonlar ortak öğeler içeriyorsa yöntem geri döner .


17
Setleri değiştirmediği veya yeni bir tane oluşturmadığı için bunu diğer çözümlere tercih edin.
devconsole

7
Ve standart JRE ve sadece ayarlanmış değil, herhangi bir Koleksiyon ile çalışır.
Pierre Henry

4
Bunun en hızlı olduğunu düşünmüyorum, kesişimin ilk unsuru bulunduğunda kısa devre yapmayacak.
Ben Horner

7
Aslında ilk ortak elemanı bulur bulmaz kısa devre yapacak
Xipo


156

Stream::anyMatch

Java 8'den beri kullanabilirsiniz Stream::anyMatch.

setA.stream().anyMatch(setB::contains)

1
Tam da aradığım şey buydu! Teşekkürler :-) Ayrıca :: sözdizimi ile değişkenleri kullanabileceğinizi bilmiyordum!
dantiston

1
@blevert, anyMatch içinde neler olduğunu açıklayabilir misiniz?
Cristiano

7
@Cristiano burada, anyMatchtüm elemanları aktaracak setAve setB.contains()hepsini çağıracak . Elemanlardan herhangi biri için "true" döndürülürse, bir bütün olarak ifade true olarak değerlendirilir. Umarım bu yardımcı olmuştur.
Alex Vulaj


31

SetsAny'yi kümeler için uygulamanın iyi bir yolu Guava Sets.intersection () yöntemini kullanmaktır .

containsAnya döner boolean, böylece çağrı şöyle görünür:

Sets.intersection(set1, set2).isEmpty()

Kümeler ayrıksa doğru, aksi halde yanlış döndürür. Bunun zaman karmaşıklığı büyük olasılıkla alıkoymaktan biraz daha iyidir çünkü orijinal setinizi değiştirmekten kaçınmak için herhangi bir klonlama yapmak zorunda değilsiniz.


3
Bu yaklaşımı kullanmanın tek dezavantajı, guava kütüphanelerini eklemeniz gerektiğidir. Bence dezavantaj değil çünkü google toplama API'leri çok güçlü.
Muhammed Adnan

@DidierL Guava Collections yardımcı programı işlevlerinin çoğu, bu işlev dahil olmak üzere , veri yapılarının görünümlerini döndürür . Yani bu durumda endişelenecek bir “set inşa etmek” diye bir şey yok. Uygulama burada okumak ve / veya javadoc'u
chut

@MohammadAdnan Diğer bir dezavantaj, tam kavşağı hesaplamasıdır - set1 ve set2 çok büyükse, bu, ortak bir öğeye sahip olup olmadıklarını kontrol etmekten çok daha fazla kaynak yoğun olacaktır (hem CPU hem de bellek açısından).
Marxama


16

Kullandığım org.apache.commons.collections.CollectionUtils

CollectionUtils.containsAny(someCollection1, someCollection2)

Hepsi bu! Her iki koleksiyonda en az bir öğe varsa true değerini döndürür .

Kullanımı basit ve işlevin adı daha müstehcen.


5

retainAll()Set arayüzünde kullanın . Bu yöntem, her iki kümede de ortak olan elemanların kesişimini sağlar. Daha fazla bilgi için API belgelerine bakın.


Yinelemeden kaçınma noktası verimlilik içinse, retainAllmuhtemelen yardımcı olmaz. AbstractCollectionYinelemede uygulanması .
yshavit

1
yshavit doğrudur. OP'nin her iki sette de herhangi bir elemanın var olup olmadığını görmek istediği göz önüne alındığında, uygun bir algoritmanın O(1)en iyi durumda bir çalışma süresi olurken retainAll, bir satır boyunca bir O(N)şey olurdu (sadece 1 setin büyüklüğüne bağlı olacaktır) en iyi çalışma süresi.
Zéychin

3

Bir oluşturma tavsiye HashMapgrubu A'dan, ve daha sonra, B yineleme ve B herhangi bir öğe bu olarak çalışır A'da ise kontrol O(|A|+|B|), oysa (çarpışmaları olması gibi) zaman retainAll(Collection<?> c)içindeki şıranın çalıştırmak O(|A|*|B|)zaman.


3

Bunu yapmak için biraz kaba bir yöntem var. Yalnızca A kümesi çağrıdan başka bir B öğesi içeriyorsa ve

A.removeAll(B)

A setini değiştirir. Bu durumda removeAll öğesi true değerini döndürür ( removeAll belgelerinde belirtildiği gibi ). Ama muhtemelen A setini değiştirmek istemezsiniz, böylece bir kopya üzerinde hareket etmeyi düşünebilirsiniz, örneğin:

new HashSet(A).removeAll(B)

ve kümeler farklı değilse, yani boş olmayan kavşakları varsa dönen değer doğru olacaktır.

Ayrıca bkz. Apache Commons Koleksiyonları


2

RetainAll yöntemini kullanabilir ve iki kümenizin kesişimini elde edebilirsiniz.


Çoğu durumda, orijinal setin saklanması gerekir, bu nedenle kullanmak retainAlliçin orijinal setin bir kopyasını oluşturmak gerekir. O zaman ZéychinHashSet tarafından önerildiği gibi kullanmak daha verimlidir .
Petr Pudlák

Bu bir durum değişikliği, durum kontrolü değil
Ben
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.