web-dev-qa-db-fra.com

Meilleure façon de convertir une ArrayList en chaîne

J'ai un ArrayList que je veux sortir complètement en tant que chaîne. Essentiellement, je veux le sortir dans l'ordre en utilisant le toString de chaque élément séparé par des tabulations. Y at-il un moyen rapide de faire cela? Vous pouvez le parcourir en boucle (ou supprimer chaque élément) et le concaténer en une chaîne, mais je pense que cela sera très lent.

353
Juan Besa

Fondamentalement, utiliser une boucle pour parcourir le ArrayList est la seule option:

N'UTILISEZ PAS ce code, continuez de lire au bas de cette réponse pour voir pourquoi ce n'est pas souhaitable et indiquez le code à utiliser à la place:

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

En fait, une concaténation de chaîne va très bien se passer, car le compilateur javac optimisera la concaténation de chaîne comme une série d'opérations append sur un StringBuilder de toute façon. Voici une partie du désassemblage du bytecode de la boucle for du programme ci-dessus:

   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;

Comme on peut le constater, le compilateur optimise cette boucle à l’aide de StringBuilder. Les performances ne devraient donc pas être un gros problème.

(OK, au deuxième regard, la StringBuilder est instanciée à chaque itération de la boucle, de sorte que ce n'est peut-être pas le bytecode le plus efficace. Instancier et utiliser un StringBuilder explicite donnerait probablement de meilleures performances.)

En fait, je pense qu'avoir une sorte de sortie (que ce soit sur disque ou à l'écran) sera au moins d'un ordre de grandeur plus lent que d'avoir à se soucier de la performance des concaténations de chaînes.

Edit: Comme indiqué dans les commentaires, l'optimisation ci-dessus du compilateur crée une nouvelle instance de StringBuilder à chaque itération. (Ce que j'ai noté précédemment.)

La technique la plus optimisée à utiliser sera la réponse de Paul Tomblin , car elle instancie un seul objet StringBuilder en dehors de la boucle for.

Réécrire dans le code ci-dessus pour:

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

Instanciera uniquement la StringBuilder une fois en dehors de la boucle et ne fera que les deux appels à la méthode append à l'intérieur de la boucle, comme le montre ce bytecode (qui montre l'instanciation de StringBuilder et la boucle):

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

Donc, effectivement, l'optimisation de la main devrait être plus performante, car l'intérieur de la boucle for est plus court et il n'est pas nécessaire d'instancier un StringBuilder à chaque itération.

315
coobird

Dans Java 8 ou version ultérieure:

String listString = String.join(", ", list);

Si la list n'est pas de type String, un collecteur de jonction peut être utilisé:

String listString = list.stream().map(Object::toString)
                        .collect(Collectors.joining(", "));
789
Vitalii Fedorenko

Si vous faites cela sur Android, il existe un utilitaire Nice appelé TextUtils qui possède une méthode .join(String delimiter, Iterable).

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

Évidemment, pas beaucoup d'utilisation en dehors d'Android, mais j'ai décidé de l'ajouter à ce fil ...

378
JJ Geewax

Téléchargez Apache Commons Lang et utilisez la méthode

 StringUtils.join(list)

 StringUtils.join(list, ", ") // 2nd param is the separator.

Vous pouvez bien sûr l'implémenter vous-même, mais leur code est entièrement testé et constitue probablement la meilleure implémentation possible.

Je suis un grand fan de la bibliothèque Apache Commons et je pense aussi que c'est un excellent ajout à la bibliothèque standard Java.

222
Ravi Wallau

C'est une question assez ancienne, mais je pense que je pourrais aussi bien ajouter une réponse plus moderne - utilisez la classe Joiner de Guava :

String joined = Joiner.on("\t").join(list);
138
Jon Skeet

Changer Liste en une lisible et explicite String est vraiment une question courante que tout le monde peut rencontrer.

Cas 1. Si vous avez StringUtils d'Apache dans votre chemin de classe (comme dans rogerdpack et Ravi Wallau):

import org.Apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);

Cas 2. Si vous souhaitez uniquement utiliser les méthodes de JDK (7):

import Java.util.Arrays;
String str = Arrays.toString(myList.toArray()); 

Ne construisez jamais de roues par vous-même, n’utilisez pas de boucle pour cette tâche d’une ligne.

79
Sheng.W

Si vous cherchez un one-liner rapide, à partir de Java 5, vous pouvez le faire:

myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")

De plus, si votre but est simplement d'imprimer le contenu et que vous vous inquiétez moins du "\ t", vous pouvez simplement faire ceci:

myList.toString()

qui retourne une chaîne comme

[str1, str2, str3]

Si vous avez un tableau (pas de tableau), vous pouvez accomplir la même chose comme ceci:

 Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
56
Ken Shih

Faites une boucle et appelez toString. Il n'y a pas de moyen magique, et s'il y en avait, que pensez-vous que cela ferait sous les couvertures autres que de le parcourir en boucle? La seule micro-optimisation consisterait à utiliser StringBuilder à la place de String, et même si ce n’est pas un gain énorme - la concaténation de chaînes se transforme en StringBuilder sous la couverture, mais au moins si vous l’écrivez de cette façon, vous pouvez voir ce qui se passe.

StringBuilder out = new StringBuilder();
for (Object o : list)
{
  out.append(o.toString());
  out.append("\t");
}
return out.toString();
38
Paul Tomblin

La plupart des projets Java disposent souvent d'Apache-commons lang. Les méthodes de StringUtils.join () sont très jolies et ont plusieurs saveurs pour répondre à presque tous les besoins.

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

Paramètres:

collection - la collection de valeurs à associer peut être nulle

separator - le séparateur à utiliser

Retourne: la chaîne jointe, null si entrée itérateur NULL

Depuis: 2.3

36
Brian

Android a une classe TextUtil que vous pouvez utiliser http://developer.Android.com/reference/Android/text/TextUtils.html

String implode = TextUtils.join("\t", list);
15
kehers

Pour ce cas d'utilisation simple, vous pouvez simplement joindre les chaînes avec une virgule. Si vous utilisez Java 8:

String csv = String.join("\t", yourArray);

sinon, commons-lang a une méthode join ():

String csv = org.Apache.commons.lang3.StringUtils.join(yourArray, "\t");
14
Khader M A

Une manière élégante de traiter les caractères de séparation finaux est d'utiliser séparateur de classe

StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();

La méthode toString de Class Separator renvoie le séparateur, à l'exception de pour le premier appel. Ainsi, nous imprimons la liste sans séparer (ou dans ce cas) les séparateurs.

13
akuhn

ArrayList class ( Java Docs ) étend AbstractList class, qui étend AbstractCollection class qui contient une méthode toString() ( Java Docs ). Donc, vous écrivez simplement

listName.toString();

Les développeurs Java ont déjà compris le moyen le plus efficace et vous l’ont fourni avec une méthode bien emballée et documentée. Appelez simplement cette méthode.

7
golddove

C'est un algorithme O(n) de toute façon (à moins que vous n'ayez utilisé une solution multi-thread où vous avez divisé la liste en plusieurs sous-listes, mais je ne pense pas que ce soit ce que vous demandez).

Utilisez juste un StringBuilder comme ci-dessous:

StringBuilder sb = new StringBuilder();

for (Object obj : list) {
  sb.append(obj.toString());
  sb.append("\t");
}

String finalString = sb.toString();

La StringBuilder sera beaucoup plus rapide que la concaténation de chaîne car vous ne réinstancierez pas un objet String à chaque concaténation.

6
Mike C.

Si vous vous trouvez sur Android et que vous n'utilisez pas encore Jack (p. Ex., Car la prise en charge d'Instant Run n’a toujours pas été prise en charge), et si vous souhaitez davantage de contrôle sur le formatage de la chaîne résultante (par exemple, vous voudriez utiliser le caractère de nouvelle ligne comme diviseur d’éléments), et utiliser/vouloir utiliser la bibliothèque StreamSupport (pour utiliser des flux sur Java 7 ou des versions antérieures du compilateur), vous pourriez utiliser quelque chose comme ceci (J'ai mis cette méthode dans ma classe ListUtils):

public static <T> String asString(List<T> list) {
    return StreamSupport.stream(list)
            .map(Object::toString)
            .collect(Collectors.joining("\n"));
}

Et bien sûr, veillez à implémenter toString () sur la classe de vos objets liste.

5
Javad Sadeqzadeh

En Java 8, c'est simple. Voir exemple de liste d'entiers:

String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "\t" + u).orElse("");

Ou version multiligne (plus simple à lire):

String result = Arrays.asList(1,2,3).stream()
    .map(Object::toString)
    .reduce((t, u) -> t + "\t" + u)
    .orElse("");

Mise à jour - une version abrégée

String result = Arrays.asList(1,2,3).stream()
                .map(Object::toString)
                .collect(Collectors.joining("\t"));
4
amra

Est-ce que ce qui suit pourrait être bon:

List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));   
3
Beezer

Si vous ne voulez pas le dernier\t après le dernier élément, vous devez utiliser l'index pour vérifier, mais rappelez-vous que cela ne fait que "fonctionner" (c'est-à-dire que O(n)) lorsque les listes implémentent le Accès aléatoire.

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());
3
So So
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()

Vous transmettez au new StringJoiner la séquence de caractères que vous voulez utiliser comme séparateur. Si vous voulez faire un CSV: new StringJoiner(", ");

3
fmsf

Le code ci-dessous peut vous aider,

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

Sortie:

Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3
3
Srinivasan.S

Peut-être pas la meilleure façon, mais élégante.

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

Sortie

[Test, Test2]

3

Si vous utilisez Eclipse Collections , vous pouvez utiliser la méthode 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 vous pouvez convertir votre ArrayList en FastList, vous pouvez vous débarrasser de l'adaptateur.

Assert.assertEquals(
    "one\ttwo\tthree",
    FastList.newListWith("one", "two", "three").makeString("\t"));

Remarque: je suis un partisan des collections Eclipse.

3
Craig P. Motlin

Pour séparer en utilisant des tabulations au lieu d'utiliser println vous pouvez utiliser print

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");
}
2
chopss

Je vois pas mal d'exemples qui dépendent de ressources supplémentaires, mais il semble que ce serait la solution la plus simple: (c'est ce que j'ai utilisé dans mon propre projet), qui consiste essentiellement à convertir un tableau ArrayList en tableau puis en liste. .

    List<Account> accounts = new ArrayList<>();

   public String accountList() 
   {
      Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
      String listingString = Arrays.toString(listingArray);
      return listingString;
   }
1
Elliander

En une ligne: de [12,0,1,78,12] à 12 0 1 78 12

String srt= list.toString().replaceAll("\\[|\\]|,","");
0
Pratyush Pranjal

La conversation est maintenant assez ancienne et Apache commons utilise désormais un StringBuilder en interne: http://commons.Apache.org/lang/api/src-html/org/Apache/commons/lang/StringUtils. html # line.3045

Comme nous le savons, cela améliorera les performances, mais si les performances sont critiques, la méthode utilisée risque d’être quelque peu inefficace. Alors que l'interface est flexible et permet un comportement cohérent entre différents types de collection, elle est quelque peu inefficace pour les listes, qui est le type de collection de la question d'origine.

Je fonde ceci sur le fait que nous encourons des frais généraux que nous éviterions en itérant simplement à travers les éléments d’une boucle for traditionnelle. Au lieu de cela, certaines choses supplémentaires se produisent en coulisse, la vérification des modifications simultanées, des appels de méthode, etc. La boucle for améliorée entraînera le même temps système car l'itérateur est utilisé sur l'objet Iterable (la liste).

0
Alex VI

Vous pouvez utiliser un regex pour cela. C'est aussi concis que possible

System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));
0
Vikrant Goel