Convertir conjunto en lista sin crear una nueva lista


503

Estoy usando este código para convertir Seta a 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);
}

Quiero evitar crear una nueva lista en cada iteración del bucle. ¿Es eso posible?


1
Sé una manera de convertir el conjunto a la lista como en Q. Quiero evitar crear una nueva lista cada vez en bucle.
Muhammad Imran Tariq

44
¿Por qué no puedes simplemente agregar el conjunto a mainList? ¿Por qué necesita convertir el conjunto en una lista?
DagR

1
¿Es su intención crear una Lista <Lista <? >>
Hiery Nomus

55
No puedes Su pregunta encarna una contradicción en los términos.
Marqués de Lorne

Respuestas:


803

Puede usar el método List.addAll () . Acepta una Colección como argumento, y su conjunto es una Colección.

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

EDITAR: como responder a la edición de la pregunta.
Es fácil ver que si desea tener a Mapcon Lists como valores, para tener k valores diferentes, necesita crear k listas diferentes.
Por lo tanto: no puede evitar crear estas listas, las listas deberán crearse.

Posible
solución : declare su Mapcomo a Map<String,Set>o en su Map<String,Collection>lugar, e inserte su conjunto


1
lo siento, era mainMap no list. ver pregunta
Muhammad Imran Tariq

@imrantariq: ¿está differentKeyNamecambiando cada iteración? ¿Realmente quieres something.size()diferentes valores posibles en tus mapas? Es fácil ver que un mapa con klistas como valores necesita crear al menos klistas.
amit

@imrantariq: ¿y quieres una lista diferente para cada clave que supongo?
amit

@imrantariq: Lo que estás solicitando es imposible. lee mi edición para más detalles.
amit

Devolverá NullPointerException en caso de que el conjunto sea nulo.
w35l3y

411

Use el constructor para convertirlo:

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

21
Dijo específicamente que quiere evitar esto.
Mapeters

3
@mook Irrelevante, ya que su requisito no es implementable.
Marqués de Lorne

16
@EJP, entonces su respuesta debe decir eso, en lugar de simplemente decir algo que el OP no pidió sin ninguna explicación.
Mapeters 01 de

lo está evitando, ese constructor usa System.arrayCopy, que realiza copias superficiales, lo que significa que solo copia las referencias de los objetos en la matriz que se usa para crear la lista. Si compara ambas colecciones, verá que ambas contienen referencias a los mismos objetos.
Gubatron

En realidad, esto no funciona en Android. ¿Alguna razón por qué?
kbluue

84

También desde la biblioteca Guava Collect, puede usar newArrayList(Collection):

Lists.newArrayList([your_set])

Esto sería muy similar a la respuesta anterior de amit , excepto que no necesita declarar (o instanciar) ningún listobjeto.


1
Si está usando guayaba, esto es útil
vsingh

66
Aunque no está llamando directamente al constructor, este método todavía llama al ArrayListconstructor.
glen3b

Si no declaro una Lista, ¿cómo puedo usar la Lista creada?
Koray Tugay

@KorayTugay, bueno, extrae Lists.newArrayList ([your_set]) en una variable (local o global). Por ejemplo: List <Foo> fooList = Lists.newArrayList (setOfFoo) Pero su pregunta es errónea. Si crea una lista, al menos se declara implícitamente (si no es así)
chaiyachaiya 01 de

1
¿Alguna idea de por qué esto hizo este método? No parece mejor que new ArrayList<>([your_set]).
DavidS

49

Podemos usar el siguiente trazador de líneas en Java 8:

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

Aquí hay un pequeño ejemplo:

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

77
Por legibilidad no se recomienda. Por ejemplo, IntelliJ sugiere "new ArrayList <> (set)" y enumera más de 20 ejemplos de código similares con los que se puede reemplazar de la misma manera.
rrhrg

¡exactamente! @rrhrg, ¿cuál es mejor para el rendimiento si usamos set.parallelStream ()?
Gaurav

31

la solucion mas simple

Quería una forma muy rápida de convertir mi conjunto a Lista y devolverlo, así que en una línea lo hice

 return new ArrayList<Long>(mySetVariable);

1
Esto también es lo que sugiere IntelliJ IDEA en lugar de las secuencias api.
Ben

6

Puede usar este cambio de una línea: 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()])));
}  

Tamaño corregido porque el nuevo Objeto [0] contendrá solo un elemento pero el nuevo Objeto [set.size ()] contendrá todos los valores
rajadilipkolli

5

Yo lo haría :

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 no se ha mencionado hasta ahora, a partir de Java 10 puede usar el nuevo copyOfmétodo de fábrica:

List.copyOf(set);

Del Javadoc :

Devuelve una Lista no modificable que contiene los elementos de la Colección dada, en su orden de iteración.


3

Java 8 ofrece la opción de usar transmisiones y puede obtener una lista de la Set<String> setStringsiguiente manera:

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

Aunque la implementación interna a partir de ahora proporciona una instancia 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);
    }

pero JDK no lo garantiza. Como se menciona aquí :

No hay garantías sobre el tipo, mutabilidad, serialización o seguridad de subprocesos de la Lista devuelta; Si se requiere un mayor control sobre la Lista devuelta, use toCollection (Proveedor).

En caso de que quiera estar seguro siempre, puede solicitar una instancia específicamente como:

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

2

Creo un staticmétodo simple :

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

... o si desea establecer el tipo de Lista, puede 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

Recientemente encontré esto:

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

1
¿Puedes ampliar o elaborar más sobre esto?
Vandal

Collections.list () crea una nueva 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 el

2

En aras de la exhaustividad...

Digamos que usted realmente hacer desea tratar los Mapvalores Lists, pero se quiere evitar copiar el Seten una Listcada vez.

Por ejemplo, tal vez estás llamando a una función de biblioteca que crea una Set, pero estás pasando tu Map<String, List<String>>resultado a una función de biblioteca (mal diseñada pero fuera de tu alcance) que solo toma Map<String, List<String>>, aunque de alguna manera sabes que las operaciones que realiza con Lists son igualmente aplicables a cualquiera Collection(y por lo tanto a cualquiera Set). Y por alguna razón , debe evitar la sobrecarga de velocidad / memoria de copiar cada Conjunto en una Lista.

En este caso de súper nicho, dependiendo del comportamiento (tal vez desconocido) que la función de biblioteca necesita de su Listcorreo electrónico, puede crear una List vista sobre cada Conjunto. Tenga en cuenta que esto es inherentemente inseguro (debido a que los requisitos de la función de biblioteca de cada uno Listpodrían presumiblemente cambiar sin que usted lo sepa), por lo que debería preferirse otra solución. Pero así es como lo harías.

Crearía una clase que implemente la Listinterfaz, tome un Seten el constructor y asigne ese conjunto a un campo, y luego use ese interno Setpara implementar la ListAPI (en la medida de lo posible y deseado).

Tenga en cuenta que algunos comportamientos de la Lista que simplemente no podrá imitar sin almacenar los elementos como a List, y algunos comportamientos que solo podrá imitar parcialmente. Nuevamente, esta clase no es un reemplazo seguro para Lists en general. En particular, si sabe que el caso de uso requiere operaciones relacionadas con el índice o MUTAR el List, este enfoque iría al sur muy rápido.

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 es realmente la única respuesta que realmente resuelve el problema planteado en la pregunta!
Lii

Puede implementar esto fácilmente extendiendo AbstractList
Lii

1

Encontré esto funcionando bien y útil para crear una Lista a partir de un 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
No has evitado crear la lista. Este código es trivialmente similar al ejemplo en su pregunta.
Taylor

2
Pero no responde a su quezon, no es que haya una respuesta.
Marqués de Lorne
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.