Como converter uma matriz em um conjunto em Java


717

Gostaria de converter uma matriz para um conjunto em Java. Existem algumas maneiras óbvias de fazer isso (por exemplo, com um loop), mas eu gostaria de algo um pouco mais limpo, algo como:

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

Alguma ideia?

Respostas:


1227

Como isso:

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

No Java 9+, se o conjunto não modificável estiver ok:

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

No Java 10+, o parâmetro de tipo genérico pode ser deduzido do tipo de componente de matrizes:

var mySet = Set.of(someArray);

10
Eu deixaria de fora o último <T>, caso contrário, seria bom!
despot

165
@dataoz: Errado; Arrays.asListé O (1).
SLaks

67
Observe que, se você usar esse método em uma matriz de primitivas, como int [], ele retornará uma List <int []>; portanto, você deve usar classes de wrapper para obter o comportamento pretendido.
22412 Mark T. Markle

6
@AjayGautam: Isso é apenas na goiaba.
SLaks

10
Vou levar a legibilidade sobre a eficiência (quase) todos os tempos: blog.codinghorror.com/...
David Carboni

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

Isso é Collections.addAll (java.util.Collection, T ...) do JDK 6.

Além disso: e se a nossa matriz estiver cheia de primitivas?

Para JDK <8, eu apenas escreveria o forloop óbvio para fazer o wrap e adicionar ao conjunto em uma única passagem.

Para JDK> = 8, uma opção atraente é algo como:

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

5
Você pode fazer isso com java.util.Collections.addAll. Além disso, eu não recomendaria mais o Commons Collections, o que significa que ele não é gerado e existe a Goiaba.
colind

14
+1 por ser mais eficiente que a resposta do SLaks, mesmo que não seja uma linha única.
Adrian

1
@ Adrian Eu questiono isso. Eu acho addAllque será O ( n ).
22613 Steve Powell

1
Acredito que o argumento de Adrian era sobre como a solução do SLaks cria uma instância de List que é descartada. O impacto real dessa diferença é provavelmente extremamente mínimo, mas pode depender do contexto em que você está fazendo isso - loops apertados ou conjuntos muito grandes podem se comportar de maneira muito diferente entre essas duas opções.
JavadocMD 22/10

13
De acordo com o javadoc Collections.addAll () (Java 6): "O comportamento deste método de conveniência é idêntico ao de c.addAll (Arrays.asList (elementos)), mas é provável que esse método seja executado significativamente mais rápido na maioria das implementações. "
Bert F

124

Com o Goiaba, você pode fazer:

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

27
também ImmutableSet.copyOf (matriz). (Eu gostaria de salientar também está, eu acho.)
Kevin Bourrillion

Para uma lista fixa de elementos, você pode usar: ImmutableSet.of (e1, e2, ..., en). Observe que você não poderá alterar este conjunto após a sua criação.
pisaruk

1
Esteja avisado, o javadoc da Goiaba diz: "Esse método não é realmente muito útil e provavelmente será preterido no futuro". Eles apontam para o padrão new HashSet<T>(Arrays.asList(someArray)). Veja google.github.io/guava/releases/19.0/api/docs/com/google/common/…
Alexander Klimetschek 11/11/16

67

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 a pena fazer isso em paralelo?
Raffi Khatchadourian

@RaffiKhatchadourian Isso não está necessariamente sendo feito em paralelo. Arrays.stream não faz nenhuma promessa no fluxo. Você teria que chamar o paralelo () no fluxo resultante para isso.
Felix S

Você também pode chamar parallelStream (). Para responder à pergunta de @ RaffiKhatchadourian, provavelmente não. Tente avaliar se você está percebendo algum problema de desempenho.
Randy the Dev

6
Geralmente, evite paralelo. Por padrão, ele usa um único pool de encadeamentos em seu aplicativo, e a sobrecarga para iniciar encadeamentos e junções é pior do que o fluxo sequencial de centenas de itens. Somente em poucas situações o paralelo realmente traz benefícios.
tkruse

45

Varargs também funcionará!

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

2
muito melhor do que 2-3 forros.
senseiwu

30

Java 8

Temos a opção de usar Streamtambém. Podemos transmitir de várias maneiras:

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);

O código fonte Collectors.toSet()mostra que os elementos são adicionados um a um a uma, HashSetmas a especificação não garante que será a HashSet.

"Não há garantias quanto ao tipo, mutabilidade, serialização ou segurança de thread do conjunto retornado".

Portanto, é melhor usar a opção posterior. A saída é: [A, B, C, D] [A, B, C, D] [A, B, C, D]

Conjunto Imutável (Java 9)

O Java 9 introduziu o Set.ofmétodo estático de fábrica que retorna um conjunto imutável para os elementos fornecidos ou a matriz.

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

Consulte Métodos de fábrica estática de conjunto imutável para obter detalhes.

Conjunto Imutável (Java 10)

Também podemos obter um conjunto imutável de duas maneiras:

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

O método Collectors.toUnmodifiableList()utiliza internamente o Set.ofintroduzido no Java 9. Verifique também esta minha resposta para obter mais informações.


1
+1 para Stream.of()- eu não conhecia esse. Uma pequena discussão sobre Collectors.toSet(): você diz que a especificação não garante a adição de elementos um por um, mas é isso que significa: "acumula ... em um novo Set". E é mais legível - tão preferível para mim, se você não precisar das garantias de tipo concreto, mutabilidade, serialização e segurança de rosca.
Andrew Spencer

A especificação @AndrewSpencer não garante que a implementação definida será HashSet. Apenas garante que será um Sete é isso que quero dizer. Espero ter esclarecido.
akhil_mittal

Desculpe, e obrigado, eu o interpretei errado, pois significa "especificação não garante a adição de uma por uma" em vez de "especificação não garante um HashSet". Propôs uma edição para esclarecer.
Andrew Spencer

19

Depois que Arrays.asList(array)você pode executarSet set = new HashSet(list);

Aqui está um método de amostra, você pode escrever:

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

Eu estava esperando por um método que retorna um conjunto diretamente de uma matriz, existe?

1
Você pode escrever o seu próprio, se você está tão ansioso :)
Petar Minchev

12

Nas Coleções Eclipse , o seguinte 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: Eu sou um confirmador das Coleções Eclipse


7

Rapidamente: você pode fazer:

// 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));

e reverter

// 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

Eu escrevi o abaixo com os conselhos acima - roube-o ... é legal!

/**
 * 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 pode ser melhor que Stream.of para o exposto acima.
Ashley Frieze

5

Tem havido uma série de grandes respostas já, mas a maioria deles não funcionará com matriz de primitivos (como int[], long[], char[], byte[], etc.)

No Java 8 e acima, você pode encaixar a matriz com:

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

Em seguida, converta para definir usando stream:

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

0

Às vezes, usar algumas bibliotecas padrão ajuda muito. Tente olhar para as coleções Apache Commons . Nesse caso, seus problemas são simplesmente transformados em algo assim

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

E aqui está o javadoc do CollectionsUtils


4
o usuário pode não usar o apache commons
Adrian

se o usuário não usar o apache commons, esse será seu primeiro erro.
precisa

3
por que você usaria isso em vez de java.util.Collections.addAll(myEmptySet, keys);??
djeikyb

0

Use CollectionUtilsou 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

No Java 10 :

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

Set.copyOfretorna um não modificável Setcontendo os elementos do dado Collection.

 O dado Collectionnão deve ser nulle não deve conter nenhum 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());

a saída é

expected size is 3: 1

mude para

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

a saída é

expected size is 3: 3

-1

Para quem resolve o Android:

Solução Kotlin Collections

O asterisco *é o spreadoperador. Aplica todos os elementos em uma coleção individualmente, cada um passado para um varargparâmetro de método. É 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)

Não passar parâmetros setOf()resulta em um conjunto vazio.

Além disso setOf, você também pode usar qualquer um destes para um tipo de hash específico:

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

É assim que define o tipo de item de coleção explicitamente.

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

-2

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

Mas acho que isso seria mais eficiente:

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

Isso não seria realmente mais eficiente (pelo menos não vale a pena pensar).
colind

3
Com a versão do construtor, a capacidade inicial do HashSeté definida com base no tamanho da matriz, por exemplo.
colind

3
esta resposta não é tão burra quanto parece: 'Collections.addAll (mySet, myArray);' de java.util.Collections usam o mesmo iterador, mas mais uma operação booleana. Plus como Bert F apontou Collections.addAll "propensos a correr significativamente mais rápido na maioria das implementações" do que c.addAll (Arrays.asList (elementos))
Zorb

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.