Liste donnée comme:
Je peux le faire avec plutôt maladroit existe-t-il une approche un peu plus élégante? Cela ne me dérange pas d'utiliser une bibliothèque si nécessaire. P> notes forte>: p> Liste George, John, Paul et Ringo Code> P> Stringbuilder code> comme tellement: p>
pour code> boucle avec un index, mais je ne cherche pas une telle solution li>
7 Réponses :
Vous pouvez rejoindre tous les éléments sauf le dernier à l'aide d'un subliste:
static String joinList(List<String> names, String firstDelimiter, String secondDelimiter) {
if (names.isEmpty()) {
return "";
} else if (names.size() == 1) {
return names.get(0);
} else {
return names.subList(0, names.size() - 1)
.stream().collect(Collectors.joining(firstDelimiter))
+ secondDelimiter + names.get(names.size() - 1);
}
}
Serait délicat d'utiliser pour une liste vide et une liste de 1 élément seulement
@Xorty en cas d'une liste vide, renvoyez une chaîne vide;).
Dans le cas d'un élément, il retournerait "et George" au lieu de "George" (contrairement à la solution d'origine)
@XORTY Vous pouvez mettre des instructions si code> avant de renvoyer le résultat souhaité, vous savez? Parce que sur la base de votre théorie, ceci et l'autre solution lancera nullpointexception code> si les noms code> sont code> sont null code> et il n'y a pas de vérification nulle.
Et c'est bien :) Ce code fait exactement ce qu'il faut faire et il s'écrase exactement quand il devrait s'écraser. Je cherchais juste une manière plus élégante. Votre solution n'est pas mauvaise, mais elle nécessiterait un groupe de si code> -s dans ce scénario.
J'ai ajouté une implémentation avec un contrôle de flux plus explicite. Il peut être plus facile de comprendre ce qu'il fait de cette façon (et cela ne crée pas de sous-langue vide dans le cas à un élément unique).
@Rasmuskaj Je voulais écrire ce code mais OP répondit dans les commentaires: Je cherchais juste une manière plus élégante. Votre solution n'est pas mauvaise, mais cela nécessiterait des tas de si-S dans ce scénario i> J'ai donc essayé d'éviter tout si. En outre, tout programmeur décent peut comprendre ce que le code fait et la création d'un subliste vide ne fera pas de mal aux performances, du moins en utilisant les implémentations de la liste fournies par le JDK.
Utilisez-vous le mot "élégant" quand ils signifient "courte"? Pendant que je ressemble personnellement à la? : Opérateur, je refuse d'appeler n'importe quel code qui contient imbriqué? : Opérateurs "Élégant". :-)
@Rasmuskaj J'appelle Elegant i> au code de haute performance, malgré la rédaction si elle est si écrite que j'ai besoin d'une pierre de Rosetta pour le traduire de manière plus lisible et comprendre ce que le code fait. Mais pour OP, on dirait que le code élégant i> est plus lisible et plus court que d'autres choses.
Si les virgules ne sont jamais dans les valeurs, c'est une doublure:
Il peut devenir un cauchemar à quelqu'un pour soutenir ce code :(
Pendant que nous sommes sur le sujet de soutenir ce code ... pourriez-vous casser la réponse et expliquer ses parties?
Vous pouvez avoir une fonction personnalisée pour ajouter le dernier délimiteur, mais pour le délimiteur entre vous pouvez utiliser stringutils.join () pour accomplir votre tâche.Vérifiez ce lien pour API P>
Je n'ai même pas besoin de cela, je les ai déjà rejoints avec la nature Java 8 - voir Collect (jointure (",")) Code> Partie
Si cela ne vous dérange pas d'utiliser un itérateur, cela fonctionne:
private static String specialJoin(Iterable<?> list, String sep, String lastSep) {
StringBuilder result = new StringBuilder();
final Iterator<?> i = list.iterator();
if (i.hasNext()) {
result.append(i.next());
while (i.hasNext()) {
final Object next = i.next();
result.append(i.hasNext() ? sep : lastSep);
result.append(next);
}
}
return result.toString();
}
Cela peut être subjectif, mais je discuterais effectivement que le code d'origine est meilleur que celui-ci :)
C'est une solution élégante i>, car elle ne traverse pas la collection plus d'une fois et ne dépend pas du contenu de la dernière valeur de la liste. :-)
J'ai écrit une autre réponse en utilisant l'API des flux / collect. Mais dans la vie réelle, j'utiliserais cette méthode à base d'itérateur.
Je ne suis pas sûr à quel point cela est élégant, mais cela fonctionne. La partie ennuyeuse est que vous devez inverser la liste Cependant, je pense que la meilleure solution est la suivante: P> code>. StringBuilder sb = new StringBuilder();
int n = list.size();
for (String string : list) {
sb.append(string);
if (--n > 0)
sb.append(n == 1 ? " and " : ", ");
}
System.out.println(sb);
Comme vous l'avez déjà fait la plupart, j'introduisais une deuxième méthode "Remplacement" qui n'est pas dans la JDK pour Java.Lang.string jusqu'à présent:
@org.junit.Test
public void test() {
List<String> names = Arrays.asList("George", "John", "Paul", "Ringo");
assertEquals("George, John, Paul and Ringo", StringUtils.asLiteralNumeration(names));
List<String> oneItemList = Arrays.asList("Paul");
assertEquals("Paul", StringUtils.asLiteralNumeration(oneItemList));
List<String> emptyList = Arrays.asList("");
assertEquals("", StringUtils.asLiteralNumeration(emptyList));
}
Pas mal, si je n'ai pas besoin de paramétrer les délimiteurs, cela peut être noms de retour.stream (). Recueillir (jointure (",")). RemplaceFirst ("(? S), (?!.! ,) "," et "); code>
Oui, bien sûr, vous pouvez le modifier à un one-liner :-)
Voici une solution élégante à l'aide de l'API de flux: malheur, cela dépend de cette fonction, qui pourrait être blanchi dans certaines catégories d'utilité: P> class Ack {
private StringBuilder result = null;
private Object last;
public void add(Object u, String sep) {
if (last != null) {
doAppend(sep, last);
}
last = u;
}
private void doAppend(String sep, Object t) {
if (result == null) {
result = new StringBuilder();
} else {
result.append(sep);
}
result.append(t);
}
public Ack merge(Ack other, String sep) {
if (other.last != null) {
doAppend(sep, last);
if (other.result != null) {
doAppend(sep, other.result);
}
last = other.last;
}
return this;
}
public String toString(String lastSep) {
if (result == null) {
return last == null ? "" : String.valueOf(last);
}
result.append(lastSep).append(last);
return result.toString();
}
}
Un collecteur personnalisé est en effet une approche élégante. Maintenant, il suffit de goûter si la plupart des développeurs sont plus heureux de comprendre peu de lignes de concaténations à cordes ou de collectionneurs personnalisés.
C'est ma première tentative d'écrire un collecteur personnalisé, il peut probablement être amélioré sur ...
@Rasmuskaj Je pense que c'est vraiment bien. Cela fonctionne certainement. La seule amélioration que je ferais, c'est que toutes ces classes anonymes dans Naturalcollector Code> peuvent être remplacées par Lambdas. Le code pour fournisseur () code> peut être juste retour ack :: nouveau; code>.
Merci pour l'indice, @pbabcdefp, j'ai mis à jour le code.
Sont des virgules jamais dans les valeurs?
@Bohemian Nope (noté que dans la question)
Pourquoi ne pas encapsuler sa fonctionnalité dans une méthode externe? Quelque chose comme
String Public String MixListofnamesAndrePlacAlastCommaMaPhOt (Liste Noms) Code> @Anatoly bien oui, mais maintenant nous parlons de la mise en œuvre