Conversión de List <Integer> en List <String>

105

Tengo una lista de enteros List<Integer>y me gustaría convertir todos los objetos enteros en cadenas, terminando así con un nuevo List<String>.

Naturalmente, podría crear un nuevo List<String>y recorrer la lista llamando String.valueOf()a cada número entero, pero me preguntaba si había una forma mejor (léase: más automática ) de hacerlo.

ChrisThomas123
fuente

Respuestas:

77

Hasta donde yo sé, iterar e instanciar es la única forma de hacer esto. Algo como (para otros posibles ayuda, ya que estoy seguro de que sabe cómo hacer esto):

List<Integer> oldList = ...
/* Specify the size of the list up front to prevent resizing. */
List<String> newList = new ArrayList<>(oldList.size());
for (Integer myInt : oldList) { 
  newList.add(String.valueOf(myInt)); 
}
jsight
fuente
Cuando es simple, esto se llama belleza.
Elbek
1
El cartel original parecía indicar que había pensado en esto, pero consideró esta solución demasiado compleja o tediosa. Pero me cuesta imaginar qué podría ser más fácil. Sí, a veces tienes que escribir 3 o 4 líneas de código para hacer un trabajo.
Jay
Pero eso te une a ArrayList. ¿Se puede hacer esto usando la misma implementación que la lista original?
alianos-
@Andreas oldList.getClass (). NewInstance () servirá
Lluis Martinez
96

Usando Google Collections de Guava-Project , puede usar el transformmétodo en la clase Lists

import com.google.common.collect.Lists;
import com.google.common.base.Functions

List<Integer> integers = Arrays.asList(1, 2, 3, 4);

List<String> strings = Lists.transform(integers, Functions.toStringFunction());

El Listdevuelto por transformes una vista en la lista de respaldo: la transformación se aplicará en cada acceso a la lista transformada.

Tenga en cuenta que Functions.toStringFunction()arrojará un NullPointerExceptioncuando se aplique a nulo, por lo que solo utilícelo si está seguro de que su lista no contendrá nulos.

Ben Lings
fuente
1
Será bueno si hay más funciones listas al lado de Functions.toStringFunction ()
ThiamTeck
1
limpio, pero quizás no tan rápido. ¿1 llamada de función adicional por valor?
h3xStream
3
HotSpot puede realizar llamadas de función en línea, por lo que si se llama lo suficiente, no debería hacer una diferencia.
Ben Lings
3
No rechazo esto porque de hecho es una solución. Pero alentar a las personas a agregar una dependencia de biblioteca para resolver una tarea tan simple es un fracaso para mí.
Estani
1
Buena solución si ya está usando guayaba en nuestra solución.
dudinha-dedalus
86

Solución para Java 8. Un poco más largo que el de Guava, pero al menos no tienes que instalar una biblioteca.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

//...

List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = integers.stream().map(Object::toString)
                                        .collect(Collectors.toList());
Trejkaz
fuente
1
Si bien esto es un poco más largo para el toStringejemplo, termina siendo más corto para las conversiones que no son compatibles con la biblioteca de funciones de Guava. Las funciones personalizadas siguen siendo fáciles, pero es mucho más código que esta transmisión de Java 8
lightswitch05
40

Lo que está haciendo está bien, pero si siente la necesidad de 'Java-it-up', puede usar un Transformer y el método de recopilación de Apache Commons , por ejemplo:

public class IntegerToStringTransformer implements Transformer<Integer, String> {
   public String transform(final Integer i) {
      return (i == null ? null : i.toString());
   }
}

..y entonces..

CollectionUtils.collect(
   collectionOfIntegers, 
   new IntegerToStringTransformer(), 
   newCollectionOfStrings);
SCdF
fuente
1
CollectionUtils.collect (collectionOfIntegers, nueva org.apache.commons.collections.functors.StringValueTransformer ()); Pero, StringValueTransformer usa String.valueOf ...
Kannan Ekanath
5
A menos que se haya realizado un nuevo trabajo en las colecciones de Apache, no hacen genéricos.
KitsuneYMG
1
Esto es realmente Java-ing-it down. Esto no es Java idiomático, sino más bien una programación funcional. Tal vez cuando tengamos cierres en Java 8, ¿podría llamarlo Java idiomático?
Christoffer Hammarström
Definitivamente desea usar Colecciones4 para eso (no las antiguas Colecciones 3.x) para soporte de genéricos: commons.apache.org/proper/commons-collections/apidocs/org/…
JRA_TLL
Definir una nueva clase solo para ser "más OOP o idiomático" ... No veo cómo esto es mejor que el simple bucle for-each. Requiere más código y aleja la funcionalidad (lo que podría mitigarse con clases anónimas, pero aún así). Este estilo funcional solo comienza a ser útil cuando hay una sintaxis decente (es decir, expresiones lambda desde Java 8), como lo han proporcionado los lenguajes funcionales durante décadas.
TheOperator
9

La fuente de String.valueOf muestra esto:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

No es que importe mucho, pero usaría toString.

Mike Polen
fuente
9

En lugar de usar String.valueOf, usaría .toString (); evita parte del boxeo automático descrito por @ johnathan.holland

El javadoc dice que valueOf devuelve lo mismo que Integer.toString ().

List<Integer> oldList = ...
List<String> newList = new ArrayList<String>(oldList.size());

for (Integer myInt : oldList) { 
  newList.add(myInt.toString()); 
}
ScArcher2
fuente
como lo señaló Tom Hawtin en la respuesta 'ganadora', no se puede instanciar List <String> ya que es solo una interfaz.
Stu Thompson
Je, lo sabía. Solo escribí el código sin probarlo. Lo arreglaré en mi respuesta.
ScArcher2
9

Aquí hay una solución de una sola línea sin trampas con una biblioteca que no es JDK.

List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", "));
Garrett Hall
fuente
7

Otra solución usando Guava y Java 8

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number));
Sandrozbinden
fuente
3

No es Java central ni genérico, pero la popular biblioteca de colecciones de bienes comunes de Yakarta tiene algunas abstracciones útiles para este tipo de tarea. Específicamente, eche un vistazo a los métodos de recopilación en

ColecciónUtils

Algo a tener en cuenta si ya está utilizando colecciones comunes en su proyecto.

serg10
fuente
4
Nunca use las colecciones de Apache. Son antiguos, desactualizados, no son aptos para el tipo y están mal escritos.
KitsuneYMG
3

Para las personas preocupadas por el "boxeo" en la respuesta de jsight: no hay ninguno. String.valueOf(Object)se utiliza aquí, y intnunca se realiza un desempaquetado .

Si usa Integer.toString()o String.valueOf(Object)depende de cómo quiera manejar posibles nulos. ¿Desea lanzar una excepción (probablemente) o tener cadenas "nulas" en su lista (tal vez)? Si es el primero, ¿quieres lanzar uno NullPointerExceptiono algún otro tipo?

Además, una pequeña falla en la respuesta de jsight: Listes una interfaz, no puede usar el nuevo operador en ella. Probablemente usaría un java.util.ArrayListen este caso, especialmente porque sabemos de antemano cuánto es probable que sea la lista.

erickson
fuente
3
List<String> stringList = integerList.stream().map((Object s)->String.valueOf(s)).collect(Collectors.toList())
Mahesh Yadav
fuente
2

@Jonathan: Podría estar equivocado, pero creo que String.valueOf () en este caso llamará a la función String.valueOf (Object) en lugar de encuadrarse en String.valueOf (int). String.valueOf (Object) simplemente devuelve "nulo" si es nulo o llama a Object.toString () si no es nulo, lo que no debería involucrar el boxeo (aunque obviamente la instanciación de nuevos objetos de cadena está involucrada).

jsight
fuente
2

Creo que usar Object.toString () para cualquier propósito que no sea la depuración es probablemente una muy mala idea, aunque en este caso los dos son funcionalmente equivalentes (asumiendo que la lista no tiene nulos). Los desarrolladores son libres de cambiar el comportamiento de cualquier método toString () sin ninguna advertencia, incluidos los métodos toString () de cualquier clase en la biblioteca estándar.

Ni siquiera se preocupe por los problemas de rendimiento causados ​​por el proceso de empaquetado / desembalaje. Si el rendimiento es crítico, simplemente use una matriz. Si es realmente crítico, no use Java. Tratar de ser más astuto que la JVM solo conducirá a dolores de cabeza.

Programador fuera de la ley
fuente
2

Una respuesta solo para expertos:

    List<Integer> ints = ...;
    String all = new ArrayList<Integer>(ints).toString();
    String[] split = all.substring(1, all.length()-1).split(", ");
    List<String> strs = Arrays.asList(split);
Tom Hawtin - tackline
fuente
Esto funciona pero a expensas de la ineficiencia. Las cadenas de Java tienen dos bytes por carácter, por lo que "," agrega un costo fijo de cuatro bytes por entero antes de contar el entero en sí ... entre otras cosas.
Robert Christian
Creo que la expresión regular podría ser más un problema en términos de eficiencia del ciclo de CPU sin procesar. En términos de memoria, supongo que una implementación razonable (asumiendo la implementación irrazonable de "Sun" de String) compartirá la misma matriz de respaldo (desde all), por lo que en realidad será bastante eficiente en memoria, lo que sería importante para el rendimiento a largo plazo. A menos que solo desee mantener uno de los elementos, por supuesto ...
Tom Hawtin - tackline
2

Lambdaj permite hacer eso de una manera muy simple y legible. Por ejemplo, suponiendo que tenga una lista de Integer y quiera convertirlos en la representación de String correspondiente, podría escribir algo así;

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
}

Lambdaj aplica la función de conversión solo mientras está iterando sobre el resultado.

Mario Fusco
fuente
1

No puede evitar la "sobrecarga de boxeo"; Los contenedores genéricos falsos de Java solo pueden almacenar objetos, por lo que sus entradas deben estar encasilladas en enteros. En principio, podría evitar la caída de Object a Integer (ya que no tiene sentido, porque Object es lo suficientemente bueno para String.valueOf y Object.toString) pero no sé si el compilador es lo suficientemente inteligente para hacer eso. La conversión de String a Object debería ser más o menos una operación no operativa, por lo que no estaría dispuesto a preocuparme por eso.

DrPizza
fuente
el compilador NO es lo suficientemente inteligente para hacer eso. Cuando se ejecuta javac, en realidad elimina toda la información de tipo genérico. La implementación subyacente de una colección de genéricos SIEMPRE almacena referencias de objetos. De hecho, puede omitir la parametrización <T> y obtener un tipo "sin procesar". "Lista l = nueva Lista ()" versus "Lista <String> l = nueva Lista <String> ()". por supuesto, esto significa que "List <String> l = (List <String>) new List <Integer> ()" en realidad se compilará y ejecutará, pero es, obviamente, muy peligroso.
Dave Dopson
1

No vi ninguna solución que siga el principio de complejidad del espacio. Si la lista de enteros tiene una gran cantidad de elementos, entonces es un gran problema.

It will be really good to remove the integer from the List<Integer> and free
the space, once it's added to List<String>.

Podemos usar el iterador para lograr lo mismo.

    List<Integer> oldList = new ArrayList<>();
    oldList.add(12);
    oldList.add(14);
    .......
    .......

    List<String> newList = new ArrayList<String>(oldList.size());
    Iterator<Integer> itr = oldList.iterator();
    while(itr.hasNext()){
        newList.add(itr.next().toString());
        itr.remove();
    }
nagendra547
fuente
1

Usando Streams: Si digamos que el resultado es una lista de enteros ( List<Integer> result) entonces:

List<String> ids = (List<String>) result.stream().map(intNumber -> Integer.toString(intNumber)).collect(Collectors.toList());

Una de las formas de solucionarlo. Espero que esto ayude.

Shirish Singh
fuente
1

Una solución un poco más concisa usando el método forEach en la lista original:

    List<Integer> oldList = Arrays.asList(1, 2, 3, 4, 5);
    List<String> newList = new ArrayList<>(oldList.size());
    oldList.forEach(e -> newList.add(String.valueOf(e)));
Solubris
fuente
0

Solo por diversión, una solución que usa el marco de unión de bifurcación jsr166y que debería estar en JDK7.

import java.util.concurrent.forkjoin.*;

private final ForkJoinExecutor executor = new ForkJoinPool();
...
List<Integer> ints = ...;
List<String> strs =
    ParallelArray.create(ints.size(), Integer.class, executor)
    .withMapping(new Ops.Op<Integer,String>() { public String op(Integer i) {
        return String.valueOf(i);
    }})
    .all()
    .asList();

(Descargo de responsabilidad: no compilado. Las especificaciones no están finalizadas. Etc.)

Es poco probable que esté en JDK7 es un poco de inferencia de tipo y azúcar sintáctico para hacer que la llamada con Mapping sea menos detallada:

    .withMapping(#(Integer i) String.valueOf(i))
Tom Hawtin - tackline
fuente
0

Esto es algo tan básico que no usaría una biblioteca externa (causará una dependencia en su proyecto que probablemente no necesite).

Tenemos una clase de métodos estáticos diseñados específicamente para realizar este tipo de trabajos. Debido a que el código para esto es tan simple, dejamos que Hotspot haga la optimización por nosotros. Este parece ser un tema en mi código recientemente: escriba un código muy simple (directo) y deje que Hotspot haga su magia. Rara vez tenemos problemas de rendimiento con un código como este: cuando aparece una nueva versión de VM, obtiene todos los beneficios de velocidad adicionales, etc.

Por mucho que me gusten las colecciones de Yakarta, no son compatibles con Genéricos y usan 1.4 como LCD. ¡Desconfío de las colecciones de Google porque se enumeran como nivel de soporte Alpha!


fuente
-1

Solo quería intervenir con una solución orientada a objetos al problema.

Si modela objetos de dominio, la solución está en los objetos de dominio. El dominio aquí es una lista de enteros para los que queremos valores de cadena.

La forma más sencilla sería no convertir la lista en absoluto.

Dicho esto, para convertir sin convertir, cambie la lista original de Integer a List of Value, donde Value se parece a esto ...

class Value {
    Integer value;
    public Integer getInt()
    {
       return value;
    }
    public String getString()
    {
       return String.valueOf(value);
    }
}

Esto será más rápido y ocupará menos memoria que copiar la lista.

¡Buena suerte!

Rodney P. Barbati
fuente