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?

Bob Gilmore
fuente

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);
SLaks
fuente
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());
JavadocMD
fuente
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);
ColinD
fuente
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]
max
fuente
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());
Alex
fuente
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.

akhil_mittal
fuente
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));
}
Petar Minchev
fuente
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

Donald Raab
fuente
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()]);
Pierre-Olivier Pignon
fuente
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());
    }
}
Ashley Frieze
fuente
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());
Julia
fuente
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

mnagni
fuente
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);
Olexandra Dmytrenko
fuente
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.

Oleksandr Pyrohov
fuente
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
Bruce Zu
fuente
-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>()
Gibolt
fuente
-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); }         
Ben S
fuente
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
-4
Set<T> b = new HashSet<>(Arrays.asList(requiredArray));
Satyendra Jaiswal
fuente
1
¿En qué aspecto responde que difiere de la implementación que @SLaks ha proporcionado hace al menos 6 años? stackoverflow.com/a/3064447
Ferrybig