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 List
toString
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é?
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();
Voir aussi # 28552
String delim = "";
for (Item i : list) {
sb.append(delim).append(i);
delim = ",";
}
org.Apache.commons.lang3.StringUtils.join(list,",");
Java 8 propose plusieurs nouvelles méthodes pour ce faire:
join
sur String
.joining
collecteur pour les flux de la classe Collectors
.StringJoiner
.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;
.
Joiner.on(",").join(myList)
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)
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é.
Il existe un joli moyen d'y parvenir en utilisant Java 8:
List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");
for(int i=0, length=list.size(); i<length; i++)
result+=(i==0?"":", ") + list.get(i);
Une option pour la boucle foreach est:
StringBuilder sb = new StringBuilder();
for(String s:list){
if (sb.length()>0) sb.append(",");
sb.append(s);
}
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.
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;)
Si vous pouvez utiliser Groovy (qui s'exécute sur la JVM):
def list = ['a', 'b', 'c', 'd']
println list.join(',')
(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() ? "," : "");
J'utilise habituellement quelque chose de similaire à la version 3. Cela fonctionne bien c/c ++/bash/...: P
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.
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
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());
}
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.
StringBuffer sb = new StringBuffer();
for (int i = 0; i < myList.size(); i++)
{
if (i > 0)
{
sb.append(", ");
}
sb.append(myList.get(i));
}
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);
}
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.
À 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();
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();
}
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, ','));
}
}
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;
}
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é?
private String betweenComma(ArrayList<String> strings) {
String united = "";
for (String string : strings) {
united = united + "," + string;
}
return united.replaceFirst(",", "");
}