2008-08-20 22 views
83

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>.Conversión de la lista <Integer> a la lista <String>

Naturalmente, podría crear un nuevo bucle List<String> ya través de la lista de llamadas String.valueOf() para cada entero, pero me preguntaba si había una (es decir: más automático) mejor manera de hacerlo?

Respuesta

64

Hasta donde yo sé, iterar y crear instancias es la única forma de hacerlo. Algo así como (para los demás ayuda potencial, 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<String>(oldList.size()) 
for (Integer myInt : oldList) { 
    newList.add(String.valueOf(myInt)); 
} 
+0

Cuando es simple, esto se llama belleza. – Elbek

+1

El cartel original parecía indicar que había pensado en esto, pero consideraba que esta solución era demasiado compleja o tediosa. Pero estoy en apuros para imaginar lo que 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

+0

Pero eso lo ata a ArrayList. ¿Se puede hacer esto usando la misma implementación que la lista original? –

2

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

9

En lugar de usar String.valueOf Usaría .toString(); evita parte del auto boxing 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()); 
} 
+0

como lo señaló Tom Hawtin en la respuesta 'ganadora', no se puede incluir la lista ya que solo es una interfaz. –

+0

Je, lo sabía. Solo escribí el código sin intentarlo. Lo arreglaré en mi respuesta. – ScArcher2

2

Creo que usando Object.toString() para cualquier otro propósito que la depuración es probablemente una mala idea, aunque en este caso los dos son funcionalmente equivalentes (suponiendo que la lista no 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 boxeo/desempaquetado. Si el rendimiento es crítico, simplemente use una matriz. Si es realmente crítico, no use Java. Tratar de ser más listo que la JVM solo conducirá a un dolor de corazón.

+0

+1 por "dolor de corazón" ... – Smalltown2k

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 me gustaría utilizar toString.

1

No se puede evitar la "sobrecarga del boxeo"; Los contenedores genéricos falsos de Java solo pueden almacenar Objetos, por lo que tus datos deben estar encuadrados en Enteros. En principio, podría evitar el downcast 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 como para hacerlo. La conversión de String a Object debería ser más o menos nula, así que no me inclinaría a preocuparme por eso.

+0

el compilador NO es lo suficientemente inteligente como 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. En realidad, puede omitir la parametrización y obtener un tipo "en bruto". "List l = new List()" versus "List l = new List ()".por supuesto, esto significa que "List l = (List ) new List ()" se compilará y se ejecutará, pero es, obviamente, muy peligroso. –

3

No se basa Java, y no genérico-ified, pero la popular biblioteca de colecciones comunes de Jakarta tiene algunas abstracciones útiles para este tipo de tarea. En concreto, echar un vistazo a los métodos de cobro contra

CollectionUtils

algo a considerar si usted ya está usando colecciones de los Comunes en su proyecto.

+4

Nunca use colecciones de Apache. Son viejos, obsoletos, no son seguros y no están bien escritos. – KitsuneYMG

39

Lo que estás haciendo está bien, pero si se siente la necesidad de 'Java-it-up' que podría utilizar un Transformer y la collect method 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); 
+0

guau, cosas geniales! – Verhogen

+1

CollectionUtils.collect (collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer()); Pero, StringValueTransformer utiliza String.valueOf ... –

+5

A menos que se haya realizado un nuevo trabajo en las colecciones apache, no hacen genéricos. – KitsuneYMG

3

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

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

Además, una pequeña falla en la respuesta de jsight: List es una interfaz, no puede usar el nuevo operador en ella. Probablemente usaría un java.util.ArrayList en este caso, especialmente dado que sabemos por adelantado cuánto tiempo será la lista.

2

una respuesta para sólo los 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); 
+0

Esto funciona pero a expensas de la ineficiencia. Las cadenas de Java son dos bytes por carácter, por lo que "," agrega un costo fijo de cuatro bytes por entero antes de contar el número entero ... entre otras cosas. –

+0

Creo que la expresión regular podría ser más un problema en términos de eficiencia del ciclo de la CPU en bruto. En términos de memoria, supongo que una implementación razonable (suponiendo que la implementación irracional de "Sun" de 'String') compartirá la misma matriz de respaldo (de' all'), por lo que en realidad será bastante eficiente con la memoria, lo que sería importante para rendimiento a largo plazo. A menos que solo desee mantener uno de los elementos, por supuesto ... –

0

Sólo por diversión, una solución mediante el jsr166y tenedor-join marco que debería 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(); 

(Negación:.. No es compilado Spec no está finalizado Etc.)

Es improbable que sea en JDK7 es un poco de inferencia de tipos y el azúcar sintáctico para hacer esa llamada withMapping menos detallado:

.withMapping(#(Integer i) String.valueOf(i)) 
0

Esto es algo tan básico que hacer 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 específicamente diseñados para hacer este tipo de trabajos. Debido a que el código para esto es tan simple, dejamos que Hotspot haga la optimización por nosotros. Esto parece ser un tema recientemente en mi código: escriba un código muy simple (sencillo) y deje que Hotspot haga su magia. Raramente tenemos problemas de rendimiento en un código como este: cuando llega una nueva versión de VM, obtienes todos los beneficios de velocidad extra, etc.

Por mucho que ame las colecciones de Yakarta, no admiten Genéricos y usan 1.4 como pantalla LCD . ¡Tengo dudas sobre las Colecciones de Google porque están enumeradas como nivel de asistencia Alfa!

82

Usando Google Collections from Guava-Project, se puede usar el método transform 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 List devuelto por transform es una vista en la lista de respaldo - la transformación se aplicará en cada acceso a la transformada lista.

Tenga en cuenta que Functions.toStringFunction() lanzará un NullPointerException cuando se aplica a nulo, por lo tanto, úsela solo si está seguro de que su lista no contendrá nulo.

+1

Sería bueno si hay más funciones listas junto a Functions.toStringFunction() – ThiamTeck

+1

limpias, pero quizás no tan rápido ... ¿1 función extra llamada por valor? – h3xStream

+3

HotSpot puede realizar llamadas de función en línea, por lo que si se llama suficiente, no debería marcar la diferencia. –

2

Lambdaj permite hacer eso de una manera muy simple y legible.Por ejemplo, suponiendo que tiene una lista de Entero y desea convertirlos en la representación de Cadena 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 itera sobre el resultado.

8

Aquí hay una solución de una línea sin hacer trampa con una biblioteca que no sea JDK.

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

+1 por causa del hackishness puro. – metasim

-1

Solo quería entrar en acción con una solución orientada a objetos para el problema.

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

La manera más fácil sería no convertir la lista en absoluto.

Dicho esto, con el fin de convertir sin convertir, cambiar la lista original de entero a la lista de Valor, Valor, donde se ve algo como 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!

52

Solución para Java 8. Un poco más largo que el de Guava, pero al menos no tiene 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()); 
+0

Si bien esto es un poco más largo para el ejemplo 'toString', termina siendo más corto para las conversiones no admitidas por la biblioteca de Funciones de Guava. Las funciones personalizadas son todavía fáciles, pero es mucho más código que esta secuencia Java 8 – lightswitch05

5

Otra solución usando la guayaba y Java 8

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

No vi ninguna solución que está siguiendo el principio de espacio complejidad. Si la lista de enteros tiene una gran cantidad de elementos, entonces es 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 utilizar iterador para lograr el 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(); 
    } 
Cuestiones relacionadas