java - cast - La mejor manera de convertir un ArrayList a una cadena
list to string java 8 (28)
¿Qué tal esta función?
public static String toString(final Collection<?> collection) {
final StringBuilder sb = new StringBuilder("{");
boolean isFirst = true;
for (final Object object : collection) {
if (!isFirst)
sb.append('','');
else
isFirst = false;
sb.append(object);
}
sb.append(''}'');
return sb.toString();
}
Funciona para cualquier tipo de colección ...
Tengo un ArrayList
que quiero mostrar completamente como una cadena. Esencialmente, quiero mostrarlo en orden usando la toString
de caracteres de cada elemento separado por pestañas. ¿Hay alguna forma rápida de hacer esto? Podrías recorrerlo (o eliminar cada elemento) y concatenarlo en una Cadena, pero creo que esto será muy lento.
¿Sería bueno lo siguiente?
List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));
Android tiene una clase TextUtil que puedes usar http://developer.android.com/reference/android/text/TextUtils.html
String implode = TextUtils.join("/t", list);
Básicamente, usar un bucle para iterar sobre ArrayList
es la única opción:
NO use este código, continúe leyendo hasta el final de esta respuesta para ver por qué no es deseable, y qué código se debe usar en su lugar:
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
String listString = "";
for (String s : list)
{
listString += s + "/t";
}
System.out.println(listString);
De hecho, una concatenación de cadenas estará bien, ya que el compilador javac
optimizará la concatenación de cadenas como una serie de operaciones de append
en un StringBuilder
todos modos. Aquí hay una parte del desmontaje del código de bytes del bucle for
del programa anterior:
61: new #13; //class java/lang/StringBuilder
64: dup
65: invokespecial #14; //Method java/lang/StringBuilder."<init>":()V
68: aload_2
69: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: aload 4
74: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
77: ldc #16; //String /t
79: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
82: invokevirtual #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
Como puede verse, el compilador optimiza ese bucle utilizando un StringBuilder
, por lo que el rendimiento no debería ser una gran preocupación.
(OK, a segunda vista, se está creando una instancia del StringBuilder
en cada iteración del bucle, por lo que puede que no sea el bytecode más eficiente. La creación de una instancia y el uso de un StringBuilder
explícito probablemente daría un mejor rendimiento).
De hecho, creo que tener cualquier tipo de salida (ya sea en el disco o en la pantalla) será al menos un orden de una magnitud más lenta que tener que preocuparse por el rendimiento de las concatenaciones de cadenas.
Edición: Como se señaló en los comentarios, la optimización del compilador anterior está creando una nueva instancia de StringBuilder
en cada iteración. (Que he notado anteriormente.)
La técnica más optimizada para usar será la respuesta de Paul Tomblin , ya que solo crea una instancia de un solo objeto StringBuilder
fuera del bucle for
.
Reescribiendo el código anterior para:
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder();
for (String s : list)
{
sb.append(s);
sb.append("/t");
}
System.out.println(sb.toString());
Solo StringBuilder
una instancia de StringBuilder
una vez fuera del bucle, y solo realizará las dos llamadas al método de append
dentro del bucle, como se evidencia en este bytecode (que muestra la creación de instancias de StringBuilder
y el bucle):
// Instantiation of the StringBuilder outside loop:
33: new #8; //class java/lang/StringBuilder
36: dup
37: invokespecial #9; //Method java/lang/StringBuilder."<init>":()V
40: astore_2
// [snip a few lines for initializing the loop]
// Loading the StringBuilder inside the loop, then append:
66: aload_2
67: aload 4
69: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: pop
73: aload_2
74: ldc #15; //String /t
76: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
79: pop
Entonces, de hecho, la optimización de la mano debería tener un mejor rendimiento, ya que el interior del bucle for
es más corto y no hay necesidad de crear una instancia de StringBuilder
en cada iteración.
Cambiar la Lista a una Cadena legible y significativa es realmente una pregunta común que todos pueden encontrar.
Caso 1 Si tiene StringUtils de apache en su ruta de clase (como de rogerdpack y Ravi Wallau):
import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);
Caso 2 . Si solo quieres usar formas de JDK (7):
import java.util.Arrays;
String str = Arrays.toString(myList.toArray());
Solo nunca construya ruedas por sí mismo, no use bucle para esta tarea de una línea.
Descarga el Jakarta Commons Lang y usa el método.
StringUtils.join(list)
Puede implementarlo usted mismo, por supuesto, pero su código está completamente probado y es probablemente la mejor implementación posible.
Soy un gran fan de la biblioteca de Jakarta Commons y también creo que es una gran adición a la biblioteca estándar de Java.
El siguiente código puede ayudarlo,
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
String str = list.toString();
System.out.println("Step-1 : " + str);
str = str.replaceAll("[//[//]]", "");
System.out.println("Step-2 : " + str);
Salida:
Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3
En Java 8 es simple. Ver ejemplo para la lista de enteros:
String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "/t" + u).orElse("");
O versión multilínea (que es más fácil de leer):
String result = Arrays.asList(1,2,3).stream()
.map(Object::toString)
.reduce((t, u) -> t + "/t" + u)
.orElse("");
En Java 8 o posterior:
String listString = String.join(", ", list);
En caso de que la list
no sea de tipo String, se puede utilizar un recopilador de unión:
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
En caso de que esté en Android y no esté usando Jack todavía (por ejemplo, porque todavía carece de soporte para Ejecución instantánea), y si desea más control sobre el formato de la cadena resultante (por ejemplo, le gustaría usar el carácter de nueva línea como el divisor de elementos), y sucede que usamos / queremos usar la biblioteca StreamSupport (para usar secuencias en Java 7 o versiones anteriores del compilador), podrías usar algo como esto (pongo este método en mi clase ListUtils):
public static <T> String asString(List<T> list) {
return StreamSupport.stream(list)
.map(Object::toString)
.collect(Collectors.joining("/n"));
}
Y, por supuesto, asegúrese de implementar toString () en la clase de objetos de su lista.
En cualquier caso, es un algoritmo O(n)
(a menos que haya hecho una solución de subprocesos múltiples en la que dividió la lista en múltiples listas, pero no creo que sea eso lo que está pidiendo).
Solo usa un StringBuilder
como se muestra abajo:
StringBuilder sb = new StringBuilder();
for (Object obj : list) {
sb.append(obj.toString());
sb.append("/t");
}
String finalString = sb.toString();
El StringBuilder
será mucho más rápido que la concatenación de cadenas porque no volverás a crear una instancia de un objeto String
en cada concatenación.
En una línea: de [12,0,1,78,12] a 12 0 1 78 12
String srt= list.toString().replaceAll("//[|//]|,","");
Esta es una conversación bastante antigua y apache commons ahora usa un StringBuilder internamente: http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line.3045
Esto, como sabemos, mejorará el rendimiento, pero si el rendimiento es crítico, entonces el método utilizado podría ser algo ineficiente. Si bien la interfaz es flexible y permitirá un comportamiento consistente en los diferentes tipos de Colección, es algo ineficiente para las Listas, que es el tipo de Colección en la pregunta original.
Baso esto en que estamos incurriendo en una sobrecarga que evitaríamos simplemente iterando a través de los elementos en un bucle tradicional. Por el contrario, suceden algunas cosas adicionales detrás de las escenas que verifican las modificaciones concurrentes, las llamadas a métodos, etc. Por otra parte, el bucle mejorado para resultará en la misma sobrecarga ya que el iterador se usa en el objeto de Iterable (la Lista).
La mayoría de los proyectos de Java a menudo tienen el lenguaje apache-commons disponible. Los métodos de StringUtils.join () son muy agradables y tienen varios sabores para satisfacer casi todas las necesidades.
public static java.lang.String join(java.util.Collection collection,
char separator)
public static String join(Iterator iterator, String separator) {
// handle null, zero and one elements before building a buffer
Object first = iterator.next();
if (!iterator.hasNext()) {
return ObjectUtils.toString(first);
}
// two or more elements
StringBuffer buf =
new StringBuffer(256); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
if (separator != null) {
buf.append(separator);
}
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
Parámetros:
colección - la colección de valores para unir, puede ser nula
separador - el caracter separador a usar
Devuelve : la cadena unida, nula si la entrada del iterador es nula
Desde: 2.3
Para este caso de uso simple, simplemente puede unir las cadenas con una coma. Si usas Java 8:
String csv = String.join("/t", yourArray);
de lo contrario commons-lang tiene un método join ():
String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "/t");
Para separar usando pestañas en lugar de usar println puede usar imprimir
ArrayList<String> mylist = new ArrayList<String>();
mylist.add("C Programming");
mylist.add("Java");
mylist.add("C++");
mylist.add("Perl");
mylist.add("Python");
for (String each : mylist)
{
System.out.print(each);
System.out.print("/t");
}
Puede que no sea la mejor manera, sino la forma elegante.
Arrays.deepToString (Arrays.asList ("Test", "Test2")
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
}
}
Salida
[Test, Test2]
Puedes usar un Regex para esto. Esto es tan conciso como se pone
System.out.println(yourArrayList.toString().replaceAll("//[|//]|[,][ ]","/t"));
Recorra a través de él y llame a toString. No hay una forma mágica, y si la hubiera, ¿qué crees que estaría haciendo bajo las coberturas aparte de recorrerla? La única micro-optimización sería usar StringBuilder en lugar de String, e incluso eso no es un gran triunfo: las cadenas de concatenación se convierten en StringBuilder debajo de las portadas, pero al menos si lo escribes de esa manera puedes ver lo que está pasando.
StringBuilder out = new StringBuilder();
for (Object o : list)
{
out.append(o.toString());
out.append("/t");
}
return out.toString();
Si está utilizando Eclipse Collections , puede usar el método makeString()
.
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Assert.assertEquals(
"one/ttwo/tthree",
ArrayListAdapter.adapt(list).makeString("/t"));
Si puede convertir su ArrayList
en un FastList
, puede deshacerse del adaptador.
Assert.assertEquals(
"one/ttwo/tthree",
FastList.newListWith("one", "two", "three").makeString("/t"));
Nota: Soy un comendador de Eclipse Collections.
Si estaba buscando una rápida de una sola línea, a partir de Java 5 puede hacer esto:
myList.toString().replaceAll("//[|//]", "").replaceAll(", ","/t")
Además, si su propósito es simplemente imprimir el contenido y le preocupa menos el "/ t", simplemente puede hacer esto:
myList.toString()
que devuelve una cadena como
[str1, str2, str3]
Si tienes un Array (no ArrayList), puedes lograr lo mismo de esta manera:
Arrays.toString(myList).replaceAll("//[|//]", "").replaceAll(", ","/t")
Si no quiere el último / t después del último elemento, debe usar el índice para verificar, pero recuerde que esto solo "funciona" (es decir, es O (n)) cuando las listas implementan el RandomAccess.
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder(list.size() * apprAvg); // every apprAvg > 1 is better than none
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
if (i < list.size() - 1) {
sb.append("/t");
}
}
System.out.println(sb.toString());
Si sucede que está haciendo esto en Android, hay una buena utilidad para este llamado TextUtils que tiene un .join(String delimiter, Iterable)
.
List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);
Obviamente no se usa mucho fuera de Android, pero pensé que lo agregaría a este hilo ...
Una forma elegante de lidiar con los caracteres de separación al final es usar el Separador de clase
StringBuilder buf = new StringBuilder();
Separator sep = new Separator("/t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();
El método toString de Separador de clase devuelve el separador, a excepción de la primera llamada. Por lo tanto, imprimimos la lista sin separar (o en este caso) los separadores iniciales.
Veo bastantes ejemplos que dependen de recursos adicionales, pero parece que esta sería la solución más simple: (que es lo que usé en mi propio proyecto) que básicamente está convirtiendo simplemente de un ArrayList a un Array y luego a una lista .
List<Account> accounts = new ArrayList<>();
public String accountList()
{
Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
String listingString = Arrays.toString(listingArray);
return listingString;
}
ArrayList
clase ArrayList
( Java Docs ) extiende la clase AbstractList
, que extiende la clase AbstractCollection
que contiene un método toString()
( Java Docs ). Así que simplemente escribe
listName.toString();
Los desarrolladores de Java ya han descubierto la forma más eficiente y se lo han ofrecido de forma bien empaquetada y documentada. Simplemente llama a ese método.
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()
new StringJoiner
al new StringJoiner
la secuencia de caracteres que deseas utilizar como separador. Si quieres hacer un CSV: new StringJoiner(", ");