¿La forma más clara de delimitar por comas una lista?


¿Cuál es la forma más clara de delimitar por comas una lista en Java?

Conozco varias maneras de hacerlo, pero me pregunto cuál es la mejor manera (donde "mejor" significa más claro y/o más corto, no el más eficiente.

Tengo una lista y quiero hacer un bucle sobre ella, imprimiendo cada valor. Quiero imprimir una coma entre cada elemento, pero no después del último (ni antes del primero).

List --> Item ( , Item ) *
List --> ( Item , ) * Item

Solución de muestra 1:

boolean isFirst = true;
for (Item i : list) {
  if (isFirst) {
    System.out.print(i);        // no comma
    isFirst = false;
  } else {
    System.out.print(", "+i);   // comma
  }
}

Solución de muestra 2-crear un sublist:

if (list.size()>0) {
  System.out.print(list.get(0));   // no comma
  List theRest = list.subList(1, list.size());
  for (Item i : theRest) {
    System.out.print(", "+i);   // comma
  }
}

Solución de muestra 3:

  Iterator<Item> i = list.iterator();
  if (i.hasNext()) {
    System.out.print(i.next());
    while (i.hasNext())
      System.out.print(", "+i.next());
  }

Estos tratan el primer elemento especialmente; uno podría tratar el último especialmente.

Por cierto, aquí está cómo List toString es implementado (se hereda de AbstractCollection), en Java 1.6:

public String toString() {
    Iterator<E> i = iterator();
    if (! i.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = i.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! i.hasNext())
            return sb.append(']').toString();
        sb.append(", ");
    }
}

Sale temprano del bucle para evitar la coma después del último elemento. Por cierto: esta es la primera vez que recuerdo haber visto " (esta Colección)"; aquí está el código para provocarlo:

List l = new LinkedList();
l.add(l);
System.out.println(l);

Acojo con satisfacción cualquier solución, incluso si usan bibliotecas inesperadas (regexp?); y también soluciones en lenguajes distintos a Java (por ejemplo, creo que Python/Ruby tienen una función intercalarse - ¿cómo se implementa que?).

Clarification: por bibliotecas, me refiero a las bibliotecas Java estándar. Para otras bibliotecas, las considero con otros idiomas, y me interesa saber cómo se implementan.

EDIT toolkit mencionó una pregunta similar: Última iteración de enhanced for loop in java

Y otro: ¿El último elemento de un bucle merece un tratamiento separado?

Author: Lii, 2009-03-21

30 answers

Para pre Java-8:

Véase también #285523

String delim = "";
for (Item i : list) {
    sb.append(delim).append(i);
    delim = ",";
}

Actualización desde Java 8:

Usando StringJoiner :

StringJoiner joiner = new StringJoiner(",");
for (Item item : list) {
    joiner.add(item.toString());
}
return joiner.toString();

Usando Stream , y Collectors :

return list.stream().
       map(Object::toString).
       collect(Collectors.joining(",")).toString();
 195
Author: toolkit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:56
org.apache.commons.lang3.StringUtils.join(list,",");
 78
Author: trunkc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-13 16:56:13

Java 8 proporciona varias formas nuevas de hacer esto:

Ejemplo:

// Util method for strings and other char sequences
List<String> strs = Arrays.asList("1", "2", "3");
String listStr1 = String.join(",", strs);

// For any type using streams and collectors
List<Object> objs = Arrays.asList(1, 2, 3);
String listStr2 = objs.stream().map(i -> i.toString()).collect(joining(",", "[", "]"));

// Using the new StringJoiner class
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.setEmptyValue("<empty>");
for (Integer i : objs) {
  joiner.add(i.toString());
}
String listStr3 = joiner.toString();

El enfoque que utiliza flujos asume import static java.util.stream.Collectors.joining;.

 32
Author: Lii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-10 12:38:57
Joiner.on(",").join(myList)

Joiner .

 17
Author: Stefan Kendall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-31 01:11:07

Basado en la lista de Java toString implementación:

Iterator i = list.iterator();
for (;;) {
  sb.append(i.next());
  if (! i.hasNext()) break;
  ab.append(", ");
}

Utiliza una gramática como esta:

List --> (Item , )* Item

Al estar basado en la última en lugar de en la primera, puede verificar la coma de salto con la misma prueba para verificar el final de la lista. Creo que este es muy elegante, pero no estoy seguro de la claridad.

 6
Author: 13ren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 12:18:36

Si usas el Framework Spring puedes hacerlo con StringUtils :

public static String arrayToDelimitedString(Object[] arr)
public static String arrayToDelimitedString(Object[] arr, String delim)
public static String collectionToCommaDelimitedString(Collection coll)
public static String collectionToCommaDelimitedString(Collection coll, String delim)
 6
Author: Henryk Konsek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-06 04:13:43
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
    sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");
 4
Author: Alfredo Osorio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-27 16:42:05

Hay una manera bonita de lograr esto usando Java 8:

List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);
 4
Author: Krishnanunni P V,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-09 13:49:18
for(int i=0, length=list.size(); i<length; i++)
  result+=(i==0?"":", ") + list.get(i);
 3
Author: cherouvim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 08:25:36

Una opción para el bucle foreach es:

StringBuilder sb = new StringBuilder();
for(String s:list){
  if (sb.length()>0) sb.append(",");
  sb.append(s);
}
 3
Author: BAH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-26 20:41:11
StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
  if (result.length()>0)
    result.append(", ");
  result.append(it.next());
}

Update : Como Dave Webb mencionó en los comentarios, esto puede no producir resultados correctos si los primeros elementos de la lista son cadenas vacías.

 2
Author: cherouvim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 09:24:48

, normalmente hago esto :

StringBuffer sb = new StringBuffer();
Iterator it = myList.iterator();
if (it.hasNext()) { sb.append(it.next().toString()); }
while (it.hasNext()) { sb.append(",").append(it.next().toString()); }

Aunque creo que voy a una esta comprobación a partir de ahora según la implementación de Java ;)

 2
Author: Alex Marshall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 12:38:00

Si puede usar Groovy (que se ejecuta en la JVM):

def list = ['a', 'b', 'c', 'd']
println list.join(',')
 2
Author: kungfoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 15:53:40

(Copiar y pegar mi propia respuesta desde aquí.) Muchas de las soluciones descritas aquí son un poco exageradas, en mi humilde opinión, especialmente aquellas que dependen de bibliotecas externas. Hay un buen lenguaje limpio y claro para lograr una lista separada por comas que siempre he usado. Se basa en el condicional (? operador:

Editar : Solución original correcta, pero no óptima según los comentarios. Intentando una segunda vez:

int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
for (int i = 0 ;  i < array.length; i++)
       builder.append(i == 0 ? "" : ",").append(array[i]);

Ahí lo tienes, en 4 líneas de código incluyendo el declaración del array y del StringBuilder.

2nd Edit : Si está tratando con un Iterador:

    List<Integer> list = Arrays.asList(1, 2, 3);
    StringBuilder builder = new StringBuilder();
    for (Iterator it = list.iterator(); it.hasNext();)
        builder.append(it.next()).append(it.hasNext() ? "," : "");
 2
Author: Julien Chastang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:56

Normalmente uso algo similar a la versión 3. Funciona bien c/c++/bash/... : P

 1
Author: sfossen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 08:16:42

No lo compilé... pero debe funcionar (o estar cerca de trabajar).

public static <T> String toString(final List<T> list, 
                                  final String delim)
{
    final StringBuilder builder;

    builder = new StringBuilder();

    for(final T item : list)
    {
        builder.append(item);
        builder.append(delim);
    }

    // kill the last delim
    builder.setLength(builder.length() - delim.length());

    return (builder.toString());
}
 1
Author: TofuBeer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-22 05:57:42

Esto es muy corto, muy claro, pero da a mi sensibilidad los horrores que se arrastran. También es un poco incómodo adaptarse a diferentes delimitadores, especialmente si es una cadena (no char).

for (Item i : list)
  sb.append(',').append(i);
if (sb.charAt(0)==',') sb.deleteCharAt(0);

Inspirado en: Última iteración del bucle for mejorado en java

 1
Author: 13ren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:37
StringBuffer sb = new StringBuffer();

for (int i = 0; i < myList.size(); i++)
{ 
    if (i > 0) 
    {
        sb.append(", ");
    }

    sb.append(myList.get(i)); 
}
 1
Author: Aries McRae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-23 00:42:00

Me gusta un poco este enfoque, que encontré en un blog hace algún tiempo. Desafortunadamente no recuerdo el nombre/URL del blog.

Puede crear una clase utility / helper que se vea así:

private class Delimiter
{
    private final String delimiter;
    private boolean first = true;

    public Delimiter(String delimiter)
    {
        this.delimiter = delimiter;
    }

    @Override
    public String toString()
    {
        if (first) {
            first = false;
            return "";
        }

        return delimiter;
    }
}

Usar la clase helper es tan simple como esto:

StringBuilder sb = new StringBuilder();
Delimiter delimiter = new Delimiter(", ");

for (String item : list) {
    sb.append(delimiter);
    sb.append(item);
}
 1
Author: Tobias Müller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-23 15:54:05

Debido a que su delimitador es ", " podría usar cualquiera de los siguientes:

public class StringDelim {

    public static void removeBrackets(String string) {
        System.out.println(string.substring(1, string.length() - 1));
    }

    public static void main(String... args) {
        // Array.toString() example
        String [] arr = {"Hi" , "My", "name", "is", "br3nt"};
        String string = Arrays.toString(arr);
        removeBrackets(string);

        // List#toString() example
        List<String> list = new ArrayList<String>();
        list.add("Hi");
        list.add("My");
        list.add("name");
        list.add("is");
        list.add("br3nt");
        string = list.toString();
        removeBrackets(string);

        // Map#values().toString() example
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("1", "Hi");
        map.put("2", "My");
        map.put("3", "name");
        map.put("4", "is");
        map.put("5", "br3nt");
        System.out.println(map.values().toString());
        removeBrackets(string);

        // Enum#toString() example
        EnumSet<Days> set = EnumSet.allOf(Days.class);
        string = set.toString();
        removeBrackets(string);
    }

    public enum Days {
        MON("Monday"),
        TUE("Tuesday"),
        WED("Wednesday"),
        THU("Thursday"),
        FRI("Friday"),
        SAT("Saturday"),
        SUN("Sunday");

        private final String day;

        Days(String day) {this.day = day;}
        public String toString() {return this.day;}
    }
}

Si su delimitador es cualquier otra cosa, entonces esto no va a funcionar para usted.

 1
Author: br3nt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-10 13:21:09

Me gusta esta solución:

String delim = " - ", string = "";

for (String item : myCollection)
    string += delim + item;

string = string.substring(delim.length());

Asumo que también puede hacer uso de StringBuilder.

 1
Author: br3nt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-11 12:53:32

En Python es fácil

",".únete (tu lista)

En C# hay un método estático en la clase String

Cadena.Join(",", yourlistofstrings)

Lo siento, no estoy seguro acerca de Java, pero pensé que me callaría cuando me preguntaste acerca de otros idiomas. Estoy seguro de que habría algo similar en Java.

 0
Author: tarn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 08:18:30

También puede agregar incondicionalmente la cadena delimitadora, y después del bucle eliminar el delimitador adicional al final. Luego, un "si la lista está vacía, devuelve esta cadena" al principio te permitirá evitar la comprobación al final (ya que no puedes eliminar caracteres de una lista vacía)

Así que la pregunta realmente es:

"Dado un bucle y un si, ¿cuál crees que es la forma más clara de tenerlos juntos?"

 0
Author: Thorbjørn Ravn Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-21 09:32:42
public static String join (List<String> list, String separator) {
  String listToString = "";

  if (list == null || list.isEmpty()) {
   return listToString;
  }

  for (String element : list) {
   listToString += element + separator;
  }

  listToString = listToString.substring(0, separator.length());

  return listToString;
}
 0
Author: user441737,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-31 01:09:30
if (array.length>0)          // edited in response Joachim's comment
  sb.append(array[i]);
for (int i=1; i<array.length; i++)
  sb.append(",").append(array[i]);

Basado en La forma más clara de delimitar por comas una lista (Java)?

Usando esta idea: ¿El último elemento de un bucle merece un tratamiento separado?

 0
Author: 13ren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:56
public String toString(List<Item> items)
{
    StringBuilder sb = new StringBuilder("[");

    for (Item item : items)
    {
        sb.append(item).append(", ");
    }

    if (sb.length() >= 2)
    {
        //looks cleaner in C# sb.Length -= 2;
        sb.setLength(sb.length() - 2);
    }

    sb.append("]");

    return sb.toString();
}
 0
Author: Eblis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-22 15:39:35

Ninguna de las respuestas usa recursión hasta ahora...

public class Main {

    public static String toString(List<String> list, char d) {
        int n = list.size();
        if(n==0) return "";
        return n > 1 ? Main.toString(list.subList(0, n - 1), d) + d
                  + list.get(n - 1) : list.get(0);
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList(new String[]{"1","2","3"});
        System.out.println(Main.toString(list, ','));
    }

}
 0
Author: langsweirdt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-12 20:45:20

En mi opinión, esto es lo más simple de leer y entender:

StringBuilder sb = new StringBuilder();
for(String string : strings) {
    sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();
 0
Author: SergeyB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-22 19:53:58
private String betweenComma(ArrayList<String> strings) {
    String united = "";
    for (String string : strings) {
        united = united + "," + string;
    }
    return united.replaceFirst(",", "");
}
 0
Author: Samet öztoprak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-28 14:02:32

Método

String join(List<Object> collection, String delimiter){
    StringBuilder stringBuilder = new StringBuilder();
    int size = collection.size();
    for (Object value : collection) {
        size --;
        if(size > 0){
            stringBuilder.append(value).append(delimiter);
        }
    }

    return stringBuilder.toString();
}

Uso

Dado el arreglo de [1,2,3]

join(myArray, ",") // 1,2,3
 -1
Author: Ilya Gazman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-29 05:47:10