2012-01-03 19 views
199

Tengo dos juegos, A y B, del mismo tipo.Algo así como 'contains any' para Java set?

tengo que encontrar si A contiene ningún elemento del conjunto B.

¿Cuál sería la mejor manera de hacerlo sin iterar sobre los conjuntos? La biblioteca Establecer tiene contains(object) y containsAll(collection), pero no containsAny(collection).

+3

¿Está tratando de evitar iteraciones por razones de eficiencia o por la limpieza del código? – yshavit

+0

Mirando las respuestas, preferiría este método si existiera ... Buena pregunta. – qben

Respuesta

354

¿No Collections.disjoint(A, B) trabajo? De la documentación:

Devuelve true si las dos colecciones especificadas no tienen elementos en común.

Por lo tanto, el método devuelve false si las colecciones contienen elementos comunes.

+8

Prefiero esto a las otras soluciones porque no modifica ninguno de los conjuntos o crea uno nuevo. – devconsole

+0

y también una solución más rápida ... – Yura

+2

Y es JRE estándar, y funciona con cualquier colección, no solo configurada. –

3

Puede usar el método retainAll y obtener la intersección de sus dos conjuntos.

+0

En la mayoría de los casos, uno necesita mantener el conjunto original, por lo que para usar 'retainAll' es necesario hacer una copia del conjunto original. Entonces es más eficiente usar 'HashSet' como lo sugiere [Zéychin] (http://stackoverflow.com/a/8708783/1333025). –

5

Use retainAll() en la interfaz Establecer. Este método proporciona una intersección de elementos comunes en ambos conjuntos. Vea los documentos API para más información.

+0

Si el objetivo de evitar la iteración es la eficiencia, 'retainAll' probablemente no ayude. Su implementación en 'AbstractCollection' se repite. – yshavit

+1

yshavit es correcto. Dado que el OP está buscando para ver si ** cualquier ** elemento existe en ambos conjuntos, un algoritmo adecuado tendría un tiempo de ejecución 'O (1)' en el mejor de los casos, mientras que 'retainAll' tendría algo en la línea de un 'O (N)' (dependerá del tamaño de solo 1 set) el mejor tiempo de ejecución. –

3

Me recomiendo crear un HashMap del conjunto A, y luego iterar a través de conjunto B y comprobando si cualquier elemento de B está en A. Esto iría en O(|A|+|B|) tiempo (como no habría colisiones), mientras que retainAll(Collection<?> c) debe ejecutar en O(|A|*|B|) vez.

3

Hay un método un poco rudo para hacer eso. Si y sólo si el conjunto contiene un elemento de algunos B de la llamada

A.removeAll(B) 

modificará el conjunto. En esta situación, removeAll devolverá verdadero (como se indica en removeAll docs). Pero probablemente no desea modificar la A establece de modo que usted puede pensar para actuar en una copia, de esta manera:

new HashSet(A).removeAll(B) 

y el valor regresar será cierto si los juegos no son distintos, es decir que tener intersección no vacía

Véase también Apache Commons Collections

23

Una buena manera de implementar containsAny para conjuntos es usando la Guava Sets.intersection().

containsAny devolvería un boolean, por lo que la llamada se ve así:

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

Esto devuelve verdadero si y sólo si los conjuntos son disjuntos, de lo contrario falso. La complejidad temporal de esto es un poco mejor que retener todo porque no es necesario clonar para evitar modificar el conjunto original.

+2

La única desventaja de utilizar este enfoque es que debe incluir bibliotecas de guayaba. Lo cual creo que no es una desventaja porque las API de colección de Google son muy fuertes. –

69

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

+0

¡Esto es exactamente lo que estaba buscando! Gracias :-) ¡Tampoco sabía que podrías usar variables con la sintaxis ::! – dantiston

+1

@blevert, ¿podría explicar qué sucede dentro de anyMatch? – Cristiano

+3

@Cristiano aquí, 'anyMatch' transmitirá todos los elementos de' setA' y llamará a 'setB.contains()' en todos ellos. Si se devuelve "verdadero" para cualquiera de los elementos, la expresión como un todo se evaluará como verdadera. Espero que esto haya ayudado. –

3

utilizo org.apache.commons.collections.CollectionUtils

CollectionUtils.containsAny(someCollection1, someCollection2) 

eso es todo! Devuelve verdadero si al menos un elemento está en ambas colecciones.

Fácil de usar, y el nombre de la función es más sugestivo.

Cuestiones relacionadas