web-dev-qa-db-fra.com

Moyen le plus clair de délimiter une liste par des virgules?

Quel est le moyen le plus clair de délimiter une liste par virgule en Java?

Je connais plusieurs façons de le faire, mais je me demande quelle est la meilleure façon (où "meilleur" signifie le plus clair et/ou le plus court, et non le plus efficace.

J'ai une liste et je veux faire une boucle dessus, en imprimant chaque valeur. Je veux imprimer une virgule entre chaque élément, mais pas après le dernier (ni avant le premier).

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

Exemple de solution 1:

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

Exemple de solution 2 - Créer une sous-liste:

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
  }
}

Exemple de solution 3:

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

Ceux-ci traitent le premier article spécialement; on pourrait plutôt traiter le dernier spécialement.

Incidemment, voici comment ListtoString est implémenté (hérité de AbstractCollection), dans 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(", ");
    }
}

Il quitte la boucle tôt pour éviter la virgule après le dernier élément. BTW: c'est la première fois que je me souviens avoir vu "(cette collection)"; voici le code pour le provoquer:

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

Je me félicite de toute solution, même si elles utilisent des bibliothèques inattendues (regexp?); ainsi que des solutions dans des langages autres que Java (par exemple, je pense que Python/Ruby ont une fonction entremêlée - comment est que implémenté?).

Clarification : par bibliothèques, je veux dire les bibliothèques standard Java. Pour les autres bibliothèques, je les considère avec d'autres langages, et intéressé à savoir comment ils sont mis en œuvre.

[~ # ~] éditer [~ # ~] Le toolkit a mentionné une question similaire: Dernière itération de la boucle for améliorée en Java

Et un autre: Le dernier élément d’une boucle mérite-t-il un traitement séparé?

100
13ren

Java 8 et ultérieur

Utilisation de StringJoiner classe:

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

En utilisant Stream , et Collectors :

return list.stream().
       map(Object::toString).
       collect(Collectors.joining(",")).toString();

Java 7 et versions antérieures

Voir aussi # 28552

String delim = "";
for (Item i : list) {
    sb.append(delim).append(i);
    delim = ",";
}
211
toolkit
org.Apache.commons.lang3.StringUtils.join(list,",");
82
trunkc

Java 8 propose plusieurs nouvelles méthodes pour ce faire:

Exemple:

// 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(Object::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();

L’approche utilisant les flux suppose que import static Java.util.stream.Collectors.joining;.

32
Lii
Joiner.on(",").join(myList)

Menuisier .

18
Stefan Kendall

Si vous utilisez Spring Framework, vous pouvez le faire avec 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)
7
Henryk Konsek

Basé sur l'implémentation List toString de Java:

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

Il utilise une grammaire comme celle-ci:

List --> (Item , )* Item

En se basant sur la dernière en lieu et place de la première, il peut vérifier s'il y a des skip-comma avec le même test pour vérifier la fin de la liste. Je pense que celui-ci est très élégant, mais je ne suis pas sûr de la clarté.

6
13ren

Il existe un joli moyen d'y parvenir en utilisant Java 8:

List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);
4
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
    sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");
4
Alfredo Osorio
for(int i=0, length=list.size(); i<length; i++)
  result+=(i==0?"":", ") + list.get(i);
3
cherouvim

Une option pour la boucle foreach est:

StringBuilder sb = new StringBuilder();
for(String s:list){
  if (sb.length()>0) sb.append(",");
  sb.append(s);
}
3
BAH
StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
  if (result.length()>0)
    result.append(", ");
  result.append(it.next());
}

Mise à jour: Comme Dave Webb l'a mentionné dans les commentaires, il est possible que les résultats ne soient pas corrects si les premiers éléments de la liste sont des chaînes vides.

2
cherouvim

Je fais habituellement ceci:

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

Bien que je pense que je vais maintenant effectuer cette vérification selon la Java;)

2
Alex Marshall

Si vous pouvez utiliser Groovy (qui s'exécute sur la JVM):

def list = ['a', 'b', 'c', 'd']
println list.join(',')
2
kungfoo

(Copier coller de ma propre réponse de ici .) La plupart des solutions décrites ici vont un peu trop haut, à mon humble avis, en particulier celles qui reposent sur des bibliothèques externes. Il existe un joli langage clair et clair permettant d’obtenir une liste séparée par des virgules que j’ai toujours utilisée. Il repose sur l'opérateur conditionnel (?):

Edit : Solution originale correcte, mais non optimale selon les commentaires. Essayer une seconde fois:

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

Voilà, en 4 lignes de code incluant la déclaration du tableau et le StringBuilder.

2nd Edit : Si vous avez affaire à un itérateur:

    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
Julien Chastang

J'utilise habituellement quelque chose de similaire à la version 3. Cela fonctionne bien c/c ++/bash/...: P

1
sfossen

J'aime cette solution:

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

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

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

Je suppose qu'il peut également utiliser StringBuilder.

1
br3nt

C'est très court, très clair, mais donne à mes sensibilités les horreurs rampantes. Il est également un peu délicat de s’adapter à différents délimiteurs, en particulier s’il s’agit d’une chaîne (pas de caractère).

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

Inspiré par: Dernière itération de la boucle for améliorée en Java

1
13ren

Je ne l'ai pas compilé ... mais je devrais travailler (ou être sur le point de travailler).

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
TofuBeer

Parce que votre délimiteur est "," vous pouvez utiliser l’un des éléments suivants:

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 votre délimiteur est RIEN, cela ne fonctionnera pas pour vous.

1
br3nt
StringBuffer sb = new StringBuffer();

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

    sb.append(myList.get(i)); 
}
1
Aries McRae

J'aime un peu cette approche, que j'ai trouvée sur un blog il y a quelque temps. Malheureusement, je ne me souviens pas du nom/de l'URL du blog.

Vous pouvez créer une classe utilitaire/helper qui ressemble à ceci:

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

Utiliser la classe helper est simple comme ceci:

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

for (String item : list) {
    sb.append(delimiter);
    sb.append(item);
}
1
Tobias Müller

Dans Python c'est facile

",". rejoindre (votre liste)

En C #, il existe une méthode statique sur la classe String

String.Join (",", yourlistofstrings)

Désolé, je ne suis pas sûr de Java mais je pensais que je vous dirais ce que vous avez demandé au sujet d'autres langues. Je suis sûr qu'il y aurait quelque chose de similaire en Java.

0
tarn

À mon avis, c'est le plus simple à lire et à comprendre:

StringBuilder sb = new StringBuilder();
for(String string : strings) {
    sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();
0
SergeyB
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
Eblis

Jusqu'à présent, aucune des réponses n'utilise la récursivité ...

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
langsweirdt

Vous pouvez également ajouter sans condition la chaîne de délimiteur et, après la boucle, supprimer le délimiteur supplémentaire à la fin. Ensuite, un "si la liste est vide alors renvoyer cette chaîne" au début vous permettra d'éviter la vérification à la fin (vous ne pouvez pas supprimer les caractères d'une liste vide)

Donc la question est vraiment:

"Avec une boucle et un if, quel est, à ton avis, le moyen le plus clair de les réunir ensemble?"

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
user441737
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]);

Basé sur Le moyen le plus clair de délimiter une liste par une virgule (Java)?

En utilisant cette idée: Le dernier élément d’une boucle mérite-t-il un traitement séparé?

0
13ren
private String betweenComma(ArrayList<String> strings) {
    String united = "";
    for (String string : strings) {
        united = united + "," + string;
    }
    return united.replaceFirst(",", "");
}
0
Samet ÖZTOPRAK