Converter conjunto em lista sem criar nova lista


503

Estou usando esse código para converter um Setem um List:

Map<String, List<String>> mainMap = new HashMap<>();

for (int i=0; i < something.size(); i++) {
  Set<String> set = getSet(...); //returns different result each time
  List<String> listOfNames = new ArrayList<>(set);
  mainMap.put(differentKeyName, listOfNames);
}

Eu quero evitar a criação de uma nova lista em cada iteração do loop. Isso é possível?


1
Eu conheço uma maneira de converter o conjunto para lista como no Q. Eu quero evitar a criação de uma nova lista a cada vez em loop.
Muhammad Imran Tariq

4
Por que você não pode simplesmente adicionar o conjunto à mainList? Por que você precisa converter o conjunto em uma lista?
Dagr

1
É sua intenção criar uma Lista <Lista <? >>
Hiery Nomus

5
Você não pode. Sua pergunta incorpora uma contradição em termos.
Marquês de Lorne

Respostas:


803

Você pode usar o método List.addAll () . Ele aceita uma coleção como argumento e seu conjunto é uma coleção.

List<String> mainList = new ArrayList<String>();
mainList.addAll(set);

EDIT: como responder à edição da pergunta.
É fácil ver que, se você deseja ter um Mapcom Lists como valores, para ter k valores diferentes, é necessário criar k listas diferentes.
Portanto: você não pode evitar a criação dessas listas, elas deverão ser criadas.

Possível
solução alternativa : Declare seu Mapcomo Map<String,Set>ou Map<String,Collection>não e apenas insira seu conjunto.


1
desculpe, foi mainMap não listar. ver pergunta
Muhammad Imran Tariq

@imrantariq: está differentKeyNamemudando todas as iterações? Deseja realmente something.size()diferentes valores possíveis em seus mapas? É fácil ver que um mapa com klistas como valores precisa criar pelo menos klistas.
11441 amit

@ imrantariq: e você quer uma lista diferente para cada chave que eu assumo?
amit

@imrantariq: O que você está solicitando é impossível. leia minha edição para mais detalhes.
11441 amit

Ele retornará NullPointerException caso o conjunto seja nulo.
W35l3y

411

Use o construtor para convertê-lo:

List<?> list = new ArrayList<?>(set);

21
Ele disse especificamente que quer evitar isso.
mapeters

3
@mook Irrelevant, pois seu requisito não é implementável.
Marquês de Lorne

16
@EJP, então sua resposta precisa dizer isso, em vez de simplesmente declarar algo que o OP não pediu sem nenhuma explicação.
mapeters

ele está evitando, que o construtor usa System.arrayCopy, que faz cópias superficiais, o que significa que apenas copia as referências dos objetos na matriz usada para criar a lista. Se você comparar as duas coleções, verá que as duas contêm referências aos mesmos objetos.
Gubatron 21/09/16

Na verdade, isso não funciona no Android. Alguma razão para isso?
kbluue

84

Também da biblioteca Guava Collect, você pode usar newArrayList(Collection):

Lists.newArrayList([your_set])

Isso seria muito semelhante à resposta anterior do amit , exceto que você não precisa declarar (ou instanciar) nenhum listobjeto.


1
Se você estiver usando goiaba, isso é útil
vsingh

6
Embora você não esteja chamando diretamente o construtor, esse método ainda chama o ArrayListconstrutor.
Glen3b 17/05

Se eu não declarar uma lista, como posso usar a lista criada?
Koray Tugay

@KorayTugay, bem, você extrai Lists.newArrayList ([your_set]) em uma variável (local ou global). Por exemplo: List <Foo> fooList = Lists.newArrayList (setOfFoo) Mas sua pergunta é falha. Se você criar uma lista, ela será declarada pelo menos implicitamente (se não explicitamente).
precisa saber é o seguinte

1
Qualquer palpite de por que isso fez esse método? Não parece melhor do que new ArrayList<>([your_set]).
21715 David15

49

Podemos usar o seguinte liner no Java 8:

List<String> list = set.stream().collect(Collectors.toList());

Aqui está um pequeno exemplo:

public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("A");
        set.add("B");
        set.add("C");
        List<String> list = set.stream().collect(Collectors.toList());
}

7
Para facilitar a leitura, não é recomendado. Por exemplo, o IntelliJ sugere "new ArrayList <> (set)" e lista mais de 20 exemplos de código semelhantes com os que podem ser substituídos da mesma maneira.
Rrhrg 11/0418

exatamente! @rrhrg, qual é o melhor desempenho se usarmos set.parallelStream ()?
gaurav

31

a solução mais simples

Eu queria uma maneira muito rápida de converter meu conjunto em Lista e devolvê-lo, então em uma linha

 return new ArrayList<Long>(mySetVariable);

1
Isso também é o que o IntelliJ IDEA sugere, em vez da API de fluxos.
Ben

6

Você pode usar esta alteração de uma linha: Arrays.asList(set.toArray(new Object[set.size()]))

Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); 
  mainMap.put(differentKeyName, Arrays.asList(set.toArray(new Object[set.size()])));
}  

Tamanho corrigida porque new Object [0] irá conter apenas um elemento, mas new Object [set.size ()] irá realizar todos os valores
rajadilipkolli

5

Eu faria :

Map<String, Collection> mainMap = new HashMap<String, Collection>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName,set);
}

5

Como não foi mencionado até o momento, no Java 10 você pode usar o novo copyOfmétodo de fábrica:

List.copyOf(set);

Do Javadoc :

Retorna uma lista não modificável que contém os elementos de uma determinada coleção, em sua ordem de iteração.


3

O Java 8 fornece a opção de usar fluxos e você pode obter uma lista Set<String> setStringcomo:

List<String> stringList = setString.stream().collect(Collectors.toList());

Embora a implementação interna a partir de agora forneça uma instância de ArrayList:

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

mas o JDK não garante isso. Como mencionado aqui :

Não há garantias sobre o tipo, mutabilidade, serialização ou segurança de thread da Lista retornada; se for necessário mais controle sobre a lista retornada, use toCollection (Supplier).

Caso você queira ter certeza sempre, poderá solicitar uma instância especificamente como:

List<String> stringArrayList = setString.stream()
                     .collect(Collectors.toCollection(ArrayList::new));

2

Eu crio um staticmétodo simples :

public static <U> List<U> convertSetToList(Set<U> set)
{
    return new ArrayList<U>(set);
}

... ou se você deseja definir o tipo de lista, pode usar:

public static <U, L extends List<U>> List<U> convertSetToList(Set<U> set, Class<L> clazz) throws InstantiationException, IllegalAccessException
{
    L list = clazz.newInstance();
    list.addAll(set);
    return list;
}

2

Recentemente eu encontrei isso:

ArrayList<T> yourList = Collections.list(Collections.enumeration(yourSet<T>));

1
Você pode expandir ou elaborar mais sobre isso?
Vandal

Collections.list () cria um novo ArrayList:public static <T> ArrayList<T> list(Enumeration<T> e) { ArrayList<T> l = new ArrayList<>(); while (e.hasMoreElements()) l.add(e.nextElement()); return l; }
Artem Lukanin

2

Por uma questão de completude ...

Diga que você realmente deseja tratar os Mapvalores como Lists, mas deseja evitar copiar os valores Setpara Listcada vez.

Por exemplo, talvez você esteja chamando uma função de biblioteca que cria a Set, mas está transmitindo o Map<String, List<String>>resultado para uma função de biblioteca (mal projetada, mas fora de suas mãos) que leva apenas Map<String, List<String>>, embora, de alguma maneira, você saiba que as operações que realiza com o Lists são igualmente aplicáveis ​​a qualquer Collection(e, portanto, a qualquer Set). E, por algum motivo, você precisa evitar a sobrecarga de velocidade / memória de copiar cada conjunto em uma lista.

Nesse caso de super nicho, dependendo do comportamento (talvez incognoscível) que a função de biblioteca precisa de seus Lists, você poderá criar uma List visualização sobre cada conjunto. Observe que isso é inerentemente inseguro (como os requisitos de cada uma das funções da biblioteca Listpodem presumivelmente mudar sem que você saiba); portanto, outra solução deve ser preferida. Mas aqui está como você faria isso.

Você criaria uma classe que implementa a Listinterface, pega um Setno construtor e atribui esse conjunto a um campo e, em seguida, usa essa interna Setpara implementar a ListAPI (na medida do possível e desejada).

Observe que alguns comportamentos de lista que você simplesmente não será capaz de imitar sem armazenar os elementos como a List, e algum comportamento que você apenas poderá imitar parcialmente. Novamente, essa classe não é um substituto seguro para o Lists em geral. Em particular, se você souber que o caso de uso requer operações relacionadas ao índice ou MUTATING the List, essa abordagem seria muito rápida.

public class ListViewOfSet<U> implements List<U> {
    private final Set<U> wrappedSet;
    public ListViewOfSet(Set<U> setToWrap) { this.wrappedSet = setToWrap; }

    @Override public int size() { return this.wrappedSet.size(); }
    @Override public boolean isEmpty() { return this.wrappedSet.isEmpty(); }
    @Override public boolean contains(Object o) { return this.wrappedSet.contains(o); }
    @Override public java.util.Iterator<U> iterator() { return this.wrappedSet.iterator(); }
    @Override public Object[] toArray() { return this.wrappedSet.toArray(); }
    @Override public <T> T[] toArray(T[] ts) { return this.wrappedSet.toArray(ts); }
    @Override public boolean add(U e) { return this.wrappedSet.add(e); }
    @Override public boolean remove(Object o) { return this.wrappedSet.remove(o); }
    @Override public boolean containsAll(Collection<?> clctn) { return this.wrappedSet.containsAll(clctn); }
    @Override public boolean addAll(Collection<? extends U> clctn) { return this.wrappedSet.addAll(clctn); }
    @Override public boolean addAll(int i, Collection<? extends U> clctn) { throw new UnsupportedOperationException(); }
    @Override public boolean removeAll(Collection<?> clctn) { return this.wrappedSet.removeAll(clctn); }
    @Override public boolean retainAll(Collection<?> clctn) { return this.wrappedSet.retainAll(clctn); }
    @Override public void clear() { this.wrappedSet.clear(); }
    @Override public U get(int i) { throw new UnsupportedOperationException(); }
    @Override public U set(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public void add(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public U remove(int i) { throw new UnsupportedOperationException(); }
    @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator() { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator(int i) { throw new UnsupportedOperationException(); }
    @Override public List<U> subList(int i, int i1) { throw new UnsupportedOperationException(); }
}

...
Set<String> set = getSet(...);
ListViewOfSet<String> listOfNames = new ListViewOfSet<>(set);
...

Esta é realmente a única resposta que realmente resolve o problema declarado na pergunta!
Lii

Você pode implementar isso facilmente, estendendo o AbstractList
Lii

1

Achei isso funcionando bem e útil para criar uma lista de um conjunto.

ArrayList < String > L1 = new ArrayList < String > ();
L1.addAll(ActualMap.keySet());
for (String x: L1) {
    System.out.println(x.toString());
}

-15
Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName, new ArrayList(set));
}

11
Você não evitou criar a lista. Esse código é trivialmente semelhante ao exemplo da sua pergunta.
Taylor

2
Mas isso não responde ao seu quezon, não que haja uma resposta.
Marquês de Lorne
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.