2012-01-03 11 views
199

Ho due set, A e B, dello stesso tipo.Qualcosa come "contiene qualsiasi" per Java set?

devo trovare se A contiene alcun elemento dal set B.

Quale sarebbe il modo migliore per farlo senza scorrere il set? La libreria Set ha contains(object) e containsAll(collection), ma non containsAny(collection).

+3

Stai cercando di evitare la ripetizione per motivi di efficienza o per la pulizia del codice? – yshavit

+0

Guardando le risposte preferirei questo metodo se esistesse ... Buona domanda. – qben

risposta

354

Non sarebbe Collections.disjoint(A, B) lavoro? Dalla documentazione:

Restituisce true se le due raccolte specificate non hanno elementi in comune.

Pertanto, il metodo restituisce false se le raccolte contengono elementi comuni.

+8

Preferisci questo alle altre soluzioni perché non modifica nessuno dei set o ne crea uno nuovo. – devconsole

+0

e anche una soluzione più rapida ... – Yura

+2

Ed è standard JRE, e funziona con qualsiasi collezione, non solo impostata. –

3

È possibile utilizzare il metodo retainAll e ottenere l'intersezione dei due set.

+0

Nella maggior parte dei casi è necessario mantenere il set originale, quindi per usare 'retainAll' è necessario creare una copia del set originale. Quindi è più efficiente usare 'HashSet' come suggerito da [Zéychin] (http://stackoverflow.com/a/8708783/1333025). –

5

Utilizzare retainAll() nell'interfaccia Set. Questo metodo fornisce un'intersezione di elementi comuni in entrambi gli insiemi. Vedi i documenti API per maggiori informazioni.

+0

Se il punto di evitare l'iterazione è per l'efficienza, 'retainAll' probabilmente non aiuterà. La sua implementazione in 'AbstractCollection' itera. – yshavit

+1

yshavit è corretto. Dato che l'OP sta cercando di vedere se ** qualsiasi ** elemento esiste in entrambi i set, un algoritmo appropriato dovrebbe avere un tempo di esecuzione 'O (1)' nel migliore dei casi, mentre 'retainAll' avrebbe qualcosa sulla falsariga di un 'O (N)' (dipende dalla dimensione di un solo set) tempo di esecuzione del caso migliore. –

3

voglio raccomandare creando un HashMap della serie A, e quindi scorrendo insieme B e controllando se ogni elemento di B è in A. Ciò eseguito in O(|A|+|B|) tempo (come ci sarebbero collisioni), che deve eseguire retainAll(Collection<?> c) nel tempo O(|A|*|B|).

3

C'è un metodo un po 'approssimativo per farlo. Se e solo se il set contiene un elemento un po 'di B rispetto alla chiamata

A.removeAll(B) 

modificherà l'un set. In questa situazione, removeAll restituirà true (come indicato allo removeAll docs). Ma probabilmente non si vuole modificare la A impostato in modo che si può pensare di agire su una copia, come in questo modo:

new HashSet(A).removeAll(B) 

e il valore di ritorno sarà vero se gli insiemi non sono distinte, vale a dire che avere intersezioni non vuote.

vedere anche Apache Commons Collections

23

Un buon modo per implementare contiene Qualsiasi per set utilizza Guava Sets.intersection().

containsAny sarebbe restituire un boolean, quindi la chiamata si presenta come:

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

Ciò restituisce vero se e solo se i set sono disgiunti, altrimenti false. La complessità temporale di questo è probabilmente leggermente migliore di retainAll perché non è necessario eseguire alcuna clonazione per evitare di modificare il set originale.

+2

L'unico svantaggio di utilizzare questo approccio è che devi includere le librerie di guava. Quale penso non sia uno svantaggio perché le API di raccolta di google sono molto forti. –

69

Dal Java 8: setA.stream().anyMatch(setB::contains)

+0

Questo è esattamente quello che stavo cercando! Grazie :-) Inoltre non sapevo che potevi usare le variabili con la sintassi ::! – dantiston

+1

@blevert, potresti spiegare cosa succede in anyMatch? – Cristiano

+3

@Cristiano qui, 'anyMatch' trasmetterà tutti gli elementi da' setA' e chiamerà 'setB.contains()' su tutti loro. Se viene restituito "true" per uno qualsiasi degli elementi, l'espressione nel suo insieme valuterà il valore true. Spero che questo abbia aiutato. –

3

io uso org.apache.commons.collections.CollectionUtils

CollectionUtils.containsAny(someCollection1, someCollection2) 

questo è tutto! Restituisce true se almeno un elemento è presente in entrambe le raccolte.

Semplice da utilizzare e il nome della funzione è più suggestivo.

Problemi correlati