Cómo convertir una matriz a un conjunto en Java


718

Me gustaría convertir una matriz a un conjunto en Java. Hay algunas formas obvias de hacer esto (es decir, con un bucle) pero me gustaría algo un poco más ordenado, algo como:

java.util.Arrays.asList(Object[] a);

¿Algunas ideas?

Respuestas:


1228

Me gusta esto:

Set<T> mySet = new HashSet<>(Arrays.asList(someArray));

En Java 9+, si el conjunto no modificable está bien:

Set<T> mySet = Set.of(someArray);

En Java 10+, el parámetro de tipo genérico se puede inferir del tipo de componente de matrices:

var mySet = Set.of(someArray);

10
Dejaría de lado el último <T>, de lo contrario, ¡es un buen revestimiento!
déspota

165
@dataoz: Incorrecto; Arrays.asListes O (1).
SLaks

67
Tenga en cuenta que si usa este método en una matriz de primitivas como int [], devolverá una Lista <int []>, por lo que debe usar clases de contenedor para obtener el comportamiento deseado.
T. Markle

66
@AjayGautam: Eso es solo en Guava.
Fugas

10
Tomaré la legibilidad sobre la eficiencia (casi) cada vez: blog.codinghorror.com/…
David Carboni

222
Set<T> mySet = new HashSet<T>();
Collections.addAll(mySet, myArray);

Eso es Collections.addAll (java.util.Collection, T ...) de JDK 6.

Además: ¿qué pasa si nuestra matriz está llena de primitivas?

Para JDK <8, simplemente escribiría el forbucle obvio para hacer el ajuste y agregar al conjunto en una sola pasada.

Para JDK> = 8, una opción atractiva es algo como:

Arrays.stream(intArray).boxed().collect(Collectors.toSet());

55
Puedes hacer eso con java.util.Collections.addAll. Además, ya no recomendaría Commons Collections, ya que no se generó y no existe Guava.
ColinD

14
+1 por ser más eficiente que la respuesta de SLaks, a pesar de que no es una línea.
Adrian

1
@ Adrian, lo cuestiono. Creo que addAllserá O ( n ).
Steve Powell

1
Creo que el punto de Adrian fue sobre cómo la solución de SLaks crea una instancia de List que finalmente se descarta. El impacto real de esa diferencia es probablemente extremadamente mínimo, pero podría depender del contexto en el que lo esté haciendo: los bucles estrechos o conjuntos muy grandes pueden comportarse de manera muy diferente entre estas dos opciones.
JavadocMD

13
Según Collections.addAll () javadoc (Java 6): "El comportamiento de este método de conveniencia es idéntico al de c.addAll (Arrays.asList (elementos)), pero es probable que este método se ejecute significativamente más rápido en la mayoría de las implementaciones. "
Bert F

124

Con guayaba puedes hacer:

T[] array = ...
Set<T> set = Sets.newHashSet(array);

27
También ImmutableSet.copyOf (array). (Me gusta señalar también, supongo.)
Kevin Bourrillion

Para una lista fija de elementos que podría usar: ImmutableSet.of (e1, e2, ..., en). Tenga en cuenta que no podrá cambiar este conjunto después de su creación.
pisaruk

1
Tenga cuidado, el javadoc de guayaba dice: "Este método no es realmente muy útil y probablemente será desaprobado en el futuro". Apuntan hacia el estándar new HashSet<T>(Arrays.asList(someArray)). Ver google.github.io/guava/releases/19.0/api/docs/com/google/common/…
Alexander Klimetschek

68

Java 8:

String[] strArray = {"eins", "zwei", "drei", "vier"};

Set<String> strSet = Arrays.stream(strArray).collect(Collectors.toSet());
System.out.println(strSet);
// [eins, vier, zwei, drei]

2
¿Vale la pena hacer esto en paralelo?
Raffi Khatchadourian

@RaffiKhatchadourian Esto no se hace necesariamente en paralelo. Arrays.stream no hace ninguna promesa en la transmisión. Tendría que llamar a parallel () en la secuencia resultante para eso.
Felix S

También puede llamar a parallelStream (). Para responder a la pregunta de @ RaffiKhatchadourian, probablemente no. Intente medir si nota problemas de rendimiento.
Randy the Dev

66
En general, evite el paralelo. De manera predeterminada, utiliza un único conjunto de subprocesos en su aplicación, y la sobrecarga para iniciar subprocesos y unirse es peor que la transmisión secuencial a través de cientos de elementos. Solo en muy pocas situaciones el paralelismo realmente trae beneficios.
tkruse

45

¡Varargs también funcionará!

Stream.of(T... values).collect(Collectors.toSet());

2
mucho mejor que 2-3 revestimientos.
senseiwu

30

Java 8

Tenemos la opción de usar Streamtambién. Podemos obtener la transmisión de varias maneras:

Set<String> set = Stream.of("A", "B", "C", "D").collect(Collectors.toCollection(HashSet::new));
System.out.println(set);

String[] stringArray = {"A", "B", "C", "D"};
Set<String> strSet1 = Arrays.stream(stringArray).collect(Collectors.toSet());
System.out.println(strSet1);

// if you need HashSet then use below option.
Set<String> strSet2 = Arrays.stream(stringArray).collect(Collectors.toCollection(HashSet::new));
System.out.println(strSet2);

El código fuente de Collectors.toSet()muestra que los elementos se agregan uno por uno a una HashSetpero la especificación no garantiza que sea a HashSet.

"No hay garantías sobre el tipo, mutabilidad, serialización o seguridad de subprocesos del conjunto devuelto".

Por lo tanto, es mejor usar la opción posterior. El resultado es: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Conjunto inmutable (Java 9)

Java 9 introdujo un Set.ofmétodo de fábrica estático que devuelve un conjunto inmutable para los elementos proporcionados o la matriz.

@SafeVarargs
static <E> Set<E> of​(E... elements)

Comprobar métodos inmutables de fábrica estática establecida para obtener más información.

Conjunto inmutable (Java 10)

También podemos obtener un conjunto inmutable de dos maneras:

  1. Set.copyOf(Arrays.asList(array))
  2. Arrays.stream(array).collect(Collectors.toUnmodifiableList());

El método Collectors.toUnmodifiableList()utiliza internamente el Set.ofintroducido en Java 9. También revise esta respuesta mía para obtener más información.


1
+1 para Stream.of()- No lo sabía. Una pequeña objeción sobre Collectors.toSet(): usted dice que la especificación no garantiza agregar elementos uno por uno, pero eso es lo que significa: "se acumula ... en un nuevo Set". Y es más legible, tan preferible para mí, si no necesita las garantías de tipo concreto, mutabilidad, serialización y seguridad de rosca.
Andrew Spencer

@AndrewSpencer Spec no garantiza que la implementación establecida sea HashSet. Solo garantiza que será un Sety eso es lo que quiero decir. Espero haberlo aclarado.
akhil_mittal

Lo sentimos, y gracias, lo leí mal porque significa "la especificación no garantiza agregar uno por uno" en lugar de "la especificación no garantiza un HashSet". Propuso una edición para aclarar.
Andrew Spencer

19

Después de hacerlo Arrays.asList(array), puedes ejecutarSet set = new HashSet(list);

Aquí hay un método de muestra, puede escribir:

public <T> Set<T> GetSetFromArray(T[] array) {
    return new HashSet<T>(Arrays.asList(array));
}

Esperaba un método que devuelva un conjunto directamente de una matriz, ¿existe alguno?

1
Puede escribir el suyo, si está tan ansioso :)
Petar Minchev

12

En Eclipse Collections , lo siguiente funcionará:

Set<Integer> set1 = Sets.mutable.of(1, 2, 3, 4, 5);
Set<Integer> set2 = Sets.mutable.of(new Integer[]{1, 2, 3, 4, 5});
MutableSet<Integer> mutableSet = Sets.mutable.of(1, 2, 3, 4, 5);
ImmutableSet<Integer> immutableSet = Sets.immutable.of(1, 2, 3, 4, 5);

Set<Integer> unmodifiableSet = Sets.mutable.of(1, 2, 3, 4, 5).asUnmodifiable();
Set<Integer> synchronizedSet = Sets.mutable.of(1, 2, 3, 4, 5).asSynchronized();
ImmutableSet<Integer> immutableSet = Sets.mutable.of(1, 2, 3, 4, 5).toImmutable();

Nota: Soy un committer para Eclipse Collections


7

Rápidamente: puedes hacer:

// Fixed-size list
List list = Arrays.asList(array);

// Growable list
list = new LinkedList(Arrays.asList(array));

// Duplicate elements are discarded
Set set = new HashSet(Arrays.asList(array));

y para revertir

// Create an array containing the elements in a list
Object[] objectArray = list.toArray();
MyClass[] array = (MyClass[])list.toArray(new MyClass[list.size()]);

// Create an array containing the elements in a set
objectArray = set.toArray();
array = (MyClass[])set.toArray(new MyClass[set.size()]);

6

He escrito lo siguiente del consejo anterior: robarlo ... ¡es bueno!

/**
 * Handy conversion to set
 */
public class SetUtil {
    /**
     * Convert some items to a set
     * @param items items
     * @param <T> works on any type
     * @return a hash set of the input items
     */
    public static <T> Set<T> asSet(T ... items) {
        return Stream.of(items).collect(Collectors.toSet());
    }
}

Arrays.stream puede ser mejor que Stream.of para lo anterior.
Ashley Frieze

5

Ha habido una gran cantidad de grandes respuestas ya, pero la mayoría de ellos no va a funcionar con gran variedad de primitivas (como int[], long[], char[],byte[] , etc.)

En Java 8 y superior, puede encajonar la matriz con:

Integer[] boxedArr = Arrays.stream(arr).boxed().toArray(Integer[]::new);

Luego convierta a set usando stream:

Stream.of(boxedArr).collect(Collectors.toSet());

0

En algún momento, usar algunas bibliotecas estándar ayuda mucho. Intenta mirar las colecciones de Apache Commons . En este caso, sus problemas simplemente se transforman en algo como esto

String[] keys = {"blah", "blahblah"}
Set<String> myEmptySet = new HashSet<String>();
CollectionUtils.addAll(pythonKeywordSet, keys);

Y aquí está el CollectionsUtils javadoc


44
el usuario podría no usar los comunes de Apache
Adrian

si el usuario no usa los recursos comunes de apache, entonces ese es su primer error.
Jeryl Cook

3
¿Por qué usarías esto en lugar de java.util.Collections.addAll(myEmptySet, keys);??
djeikyb

0

Usar CollectionUtilso ArrayUtilsdestanford-postagger-3.0.jar

import static edu.stanford.nlp.util.ArrayUtils.asSet;
or 
import static edu.stanford.nlp.util.CollectionUtils.asSet;

  ...
String [] array = {"1", "q"};
Set<String> trackIds = asSet(array);

0

En Java 10 :

String[] strs = {"A", "B"};
Set<String> set = Set.copyOf(Arrays.asList(strs));

Set.copyOfdevuelve un no modificable que Setcontiene los elementos de lo dado Collection.

 Lo dado Collectionno debe ser null, y no debe contener ningún nullelemento.


0
private Map<Integer, Set<Integer>> nobreaks = new HashMap();
nobreaks.put(1, new HashSet(Arrays.asList(new int[]{2, 4, 5})));
System.out.println("expected size is 3: " +nobreaks.get(1).size());

la salida es

expected size is 3: 1

cámbielo a

nobreaks.put(1, new HashSet(Arrays.asList( 2, 4, 5 )));

la salida es

expected size is 3: 3

-1

Para cualquiera que resuelva para Android:

Solución de colecciones Kotlin

El asterisco *es el spreadoperador. Aplica todos los elementos de una colección individualmente, cada uno pasado para un varargparámetro de método. Es equivalente a:

val myArray = arrayOf("data", "foo")
val mySet = setOf(*myArray)

// Equivalent to
val mySet = setOf("data", "foo")

// Multiple spreads ["data", "foo", "bar", "data", "foo"]
val mySet = setOf(*myArray, "bar", *myArray)

Si no se pasan parámetros, se setOf()genera un conjunto vacío.

Además setOf, también puede usar cualquiera de estos para un tipo de hash específico:

hashSetOf()
linkedSetOf()
mutableSetOf()
sortableSetOf()

Así es como se define el tipo de elemento de colección explícitamente.

setOf<String>()
hashSetOf<MyClass>()

-2

new HashSet<Object>(Arrays.asList(Object[] a));

Pero creo que esto sería más eficiente:

final Set s = new HashSet<Object>();    
for (Object o : a) { s.add(o); }         

Eso realmente no sería más eficiente (al menos no vale la pena pensarlo).
ColinD

3
Con la versión de constructor, la capacidad inicial del HashSetse establece en función del tamaño de la matriz, por ejemplo.
ColinD

3
esta respuesta no es tan tonta como parece: 'Collections.addAll (mySet, myArray);' from java.util.Collections usa el mismo iterador pero más una operación booleana. Además, como señaló Bert F Collections.addAll "es probable que se ejecute significativamente más rápido en la mayoría de las implementaciones" que c.addAll (Arrays.asList (elementos))
Zorb

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.