11
votes

Quel est le moyen le plus élégant de concaténer une liste de valeurs avec Délimiter en Java?

Je n'ai jamais trouvé de manière nette (ER) de faire ce qui suit.

Dites que j'ai une liste / une palette de chaînes. p> xxx pré>

et je veux Concaténate les dans une seule chaîne délimitée par une virgule comme suit: p> xxx pré>

en Java, si j'écris quelque chose comme ça (pardon la syntaxe), P>

...
for (int i = 0; i < list.length; i++)
{
   str = str + list[i];
   if (i != list.length - 1)
   {
     str = str + ",";
   }
}
...


8 Réponses :


2
votes

Regardez ici:

http://snippets.dzone.com/posts/show/91

Pour une discussion complète de ce sujet.


2 commentaires

Merci pour le lien. Je cherche une approche plus élégante (peut-être celle qui implique moins de lignes de code). La performance, dans mon cas, n'est pas une préoccupation majeure.


Je n'aime pas les chèques dans le look quand vous pouvez le faire à l'extérieur



10
votes

Voici ma version: astuces Java: moyen le plus rapide de collecter des objets dans une chaîne xxx

comme bonus supplémentaire: si votre code dans la boucle est plus complexe, cette approche produira une Résultats corrects sans complexe si () s.

Notez également qu'avec des processeurs modernes, l'affectation ne se produira que dans le cache (ou probablement uniquement dans un registre).

Conclusion: Bien que ce code a l'air étrange au premier coup d'œil, il présente de nombreux avantages.


14 commentaires

Ce n'est pas très jolie - faire une initialisation de Delim chaque itération.


Veuillez fournir votre solution en cas de suppression de votre message de blog.


+1 C'est ce que je fais aussi. Avez-vous des chiffres de performance pour prouver que nous avons raison?


@Gonzo: si () est plus lent qu'une assignation. L'affectation est juste une opération de pointeur et il arrive toujours avec la même adresse. La CPU utilisera donc probablement des registres et gardera tout dans le cache. De plus, le code est compact, la configuration est constante (pas besoin de faire partie du travail en dehors de la boucle) et le code dans la boucle est toujours identique.


Parler de ce degré de modification de performance est ridicule de toute façon. N'est-ce pas? Eh bien, puis montrez-moi une usecase où vous devez faire passer cette nanoseconde supplémentaire ...


Je viens de faire un test de performance rapide. Statistiquement parlant, il n'y a pas de différence que ce soit. Vraiment, un if () est lent?


@Aaron: Je vais convenir que c'est plus compact. Plus rapide, non. Même si vous écriviez en montage direct, cela ne va pas faire la différence. De plus, les compilateurs intelligents se dérouleront et l'optimisent de toute façon.


... mais de parler de code de nettoyage: Utilisation de Builder.setlength (Builder.Length () - 1); Une fois la boucle est probablement la plus propre (et ne nécessite pas de système . ArrayCopy (..) Comme delsetecharat (int) fait)


@Kle: Non, mais comme ma boucle ne contient pas de code conditionnel, je suis sûr.


@sfussenegger: Cela pourrait provoquer la mémoire tampon d'allouer plus de mémoire car ce caractère unique ne convient pas à ce que vous avez un arraycopy .


@Gonzo: Si () signifie une branche et qui coûte toujours plus cher, même si vous ne remarquez pas une différence d'exécution. Au mieux, le matériel de prévision de la succursale du processeur doit être exécuté qui coûte au moins une puissance, entraînant une chaleur, ce qui entraîne le vieillissement prématuré de votre processeur. ;) Exécutez ce code avec Java 1.1 et sur une CPU de Pentium et effectue toujours. Exécutez-le sur un netbook. En outre, le code est très clair, lisible et évident et il est très similaire dans n'importe quelle langue.


@Aaron Digulla: Je comparais une longueur de consigne (Builder.Length () - 1) sur DeleTecharat (Builder.Length ()) qui font de même mais le premier avec beaucoup moins de frais généraux. Vous avez raison, un personnage supplémentaire pourrait provoquer une arraycopie supplémentaire - mais les chances sont minimes, en particulier pour des cordes d'une taille où la vitesse importe vraiment (la taille du tampon sous-jacent toujours en double). Mais il est toujours ridicule de parler de la performance à ce niveau de toute façon. Je m'en fiche vraiment si mon CPU meurt 5 minutes plus tôt car il ne pouvait pas prédire les succursales. Bon sang, si ce n'était pas capable de le faire, il le méritait de toute façon! ;)


@ St.shadow: Non, ce n'est pas un bug de performance. Parce que la corde littérale dans le pool de cordes. Ce n'est pas une nouvelle mémoire de tasse de tas. La seule opération qui se passe est simplement d'attribuer la variable à un pointeur (qui pointe vers le pool de cordes).


Si c'est assez lent, il provoque une prédiction de Brense où elle doit deviner de quelle manière le code va brancher et remplir le cache en fonction de cette hypothèse, si elle devine mal, il doit ressortir et ressusciter le cach-cache, mais même ceci est idiot de s'inquiéter de choses comme ce changement avec la version CPU & Java. Devenir un expert à l'optimisation signifie que vos experticies seront obsolètes et probablement faux en deux ans.



-1
votes

J'utiliserais un Stringbuffer pour implémenter cette fonctionnalité. String est immuable de sorte que chaque fois que vous avez concatez deux String S, un nouvel objet est créé.

plus efficace est l'utilisation de Stringbuffer : < / p> xxx


1 commentaires

Vous ne devriez pas utiliser Stringbuffer où ce n'est pas nécessaire, c'est le fil sûr et lent, j'utiliserais StressBuilder à la place. Vous devez également supprimer la dernière virgule



3
votes
StringBuilder builder = new StringBuilder();
for (String st: list) {
    builder.append(st).append(',');
}
builder.deleteCharAt(builder.length());
String result = builder.toString();
Do not use '+' for string contacenations. It`s slow.

0 commentaires

-1
votes
for (int i = 0; i < list.length-1; i++) {
    str = str + list[i];
    str = str + ",";    
}
str = str + list[list.length-1] 

2 commentaires

L'utilisation de la concaténation de la chaîne n'est pas très rapide. Ce code est également difficile à lire, je pense


Je sais que la concaténation de la chaîne n'est pas rapide ce n'est pas le point et oui, c'est moins lisible, soulignant d'autres options pour faire ce que l'OP a demandé



2
votes

Je parie qu'il y a plusieurs classes nommées "Stringutil", "Stringutil", "Strings" ou quoi que ce soit le long de ces lignes sur la classe de classe de tout projet Java de taille moyenne. Très probablement, l'un d'entre eux fournira une fonction de jointure. Voici quelques exemples que j'ai trouvés dans mon projet:

public static final MyStringUtils {
    private MyStringUtils() {}

    public static String join(Object[] list, String delim) {
        return org.apache.commons.lang.StringUtils.join(list, delim);
    }
}


2 commentaires

Pourquoi créeriez-vous une nouvelle classe juste pour envelopper un appel à org.apache.commons.lang.stringutils.join? Comment puis-t-il supprimer les dépendances externes?


@Derekspringer Il ne supprime pas la dépendance externe. Cacher la dépendance à quelque chose comme MyStringutils ne permet que de modifier la mise en œuvre. En conséquence, on pourrait supprimer la dépendance externe en modifiant uniquement la classe MyStringutils.



11
votes

6 commentaires

+1 pour Google-collections. Oui, oui, je sais - 'une dépendance externe juste pour une jonction de string?!?!' ' - Mais cela peut rendre votre code tellement plus court + plus expressif que, si vous apprenez l'API, cela vous paiera en une heure. :)


Une fois que vous avez un coup d'œil à l'API, vous utiliserez IST pour bien plus que des jonctions de string.


Vous avez raison - si l'API externe peut être utilisé plus qu'une fois - c'est la meilleure solution.


@Thorbjorn: voir YouTube.com/watch?v=zeo_j2ochym et youtube.com/watch?v=9ni_kekhfto Pour une explication approfondie Pourquoi vous devriez utiliser GC. Il simplifie beaucoup de la chaudière lors de l'utilisation de presque toutes les structures de données complexes en Java.


Pourquoi c'est cool: maintenant, vous voulez sauter sur NULLS? Il suffit d'insérer '.skipnulls ()' entre les appels "sur" et "rejoindre". Ou traiter des nulls comme des chaînes vides? Facile, c'est '.uchefornull ("")'. Etc.


Cool - Je ne le savais pas avant. Il est temps de jeter notre propre strongutils.join () utilitaire ... :)



0
votes

Vérifiez si cela est utile: xxx


0 commentaires