web-dev-qa-db-fra.com

Rejoindre une liste <String> en Java avec des virgules et "et"

À partir d'une liste

List<String> l = new ArrayList<String>();
l.add("one");
l.add("two");
l.add("three");

J'ai une méthode

String join(List<String> messages) {
        if (messages.isEmpty()) return "";
        if (messages.size() == 1) return messages.get(0);
        String message = "";
        message = StringUtils.join(messages.subList(0, messages.size() -2), ", ");
        message = message + (messages.size() > 2 ? ", " : "") + StringUtils.join(messages.subList(messages.size() -2, messages.size()), ", and ");
        return message;
    }

qui, pour l, produit "un, deux et trois" . Ma question est la suivante: existe-t-il une méthode standard (Apache-commons) qui fait la même chose?, par exemple

WhatEverUtils.join(l, ", ", ", and ");

Clarifier. Mon problème est que cette méthode ne fonctionne pas. Cela fonctionne comme je le veux, c'est testé et tout va bien. Mon problème est que je ne pouvais pas trouver un module similaire à Apache-commons qui implémente une telle fonctionnalité. Ce qui me surprend, je ne peux pas être le premier à en avoir besoin.

Mais alors peut-être que tout le monde vient de faire

StringUtils.join(l, ", ").replaceAll(lastCommaRegex, ", and");
42
slipset

En Java 8, vous pouvez utiliser String.join() comme suit:

Collection<String> elements = ....;
String result = String.join(", ", elements);
48
Ali Dehghani

Qu'en est-il join from: org.Apache.commons.lang.StringUtils

Exemple:

StringUtils.join(new String[] { "one", "two", "three" }, ", "); // one, two, three

Pour avoir "et" ou ", et" vous pouvez simplement remplacer la dernière virgule.

16
smas

J'aime utiliser les collections Google à cette fin. Propre et très utile:

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

Ce type de code a été écrit maintes et maintes fois et vous devriez plutôt être libéré pour implémenter votre logique d’implémentation spécifique.

Si vous utilisez maven, voici la dépendance:

<dependency>
  <groupId>com.google.collections</groupId>
  <artifactId>google-collections</artifactId>
  <version>1.0</version>
</dependency>

Il a aussi beaucoup d'autres fonctionnalités intéressantes!

EDIT: Par souci d’exhaustivité, cela produira la liste "un, deux et trois".

List<String> originalList = Arrays.asList("one", "two", "three");
Joiner.on(", ").join(originalList.subList(0, originalList.size() - 1))
  .concat(", and ").concat(originalList.get(originalList.size() - 1));
14
Jaco Van Niekerk

Avec Java 8, vous pouvez utiliser des flux avec des membres.

Collection<String> strings;
...
String commaDelimited = strings.stream().collect(Collectors.joining(","));
// use strings.parallelStream() instead, if you think
//   there are gains to be had by doing fork/join
8
CppNoob

D'autres réponses parlent de "remplacer la dernière virgule", ce qui n'est pas sûr si le dernier terme contient lui-même une virgule.

Plutôt que d'utiliser une bibliothèque, vous pouvez simplement utiliser une ligne (bien que longue) de code JDK:

public static String join(List<String> msgs) {
    return msgs == null || msgs.size() == 0 ? "" : msgs.size() == 1 ? msgs.get(0) : msgs.subList(0, msgs.size() - 1).toString().replaceAll("^.|.$", "") + " and " + msgs.get(msgs.size() - 1);
}

Voir une démonstration live de ce code traitant tous les cas Edge.


Pour votre information, voici deux lignes plus lisibles:

public static String join(List<String> msgs) {
    int size = msgs == null ? 0 : msgs.size();
    return size == 0 ? "" : size == 1 ? msgs.get(0) : msgs.subList(0, --size).toString().replaceAll("^.|.$", "") + " and " + msgs.get(size);
}
4
Bohemian

Pour produire une sortie grammaticale en anglais, vous devez prendre en compte trois cas lors de la concaténation d'une liste de chaînes:

  1. "UNE"

  2. "A et B"

  3. "A, B et C.

Ceci peut être accompli en utilisant Java ou Guava standard comme ci-dessous. Les solutions sont fondamentalement les mêmes et vous permettent de choisir ce que vous voulez utiliser.

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;

import org.junit.Test;

import Java.util.List;

import static org.junit.Assert.assertEquals;

public class JoinListTest {

    @Test
    public void test_join() {
        // create cases (don't need to use ImmutableList builder from guava)
        final List<String> case1 = new ImmutableList.Builder<String>().add("A").build();
        final List<String> case2 = new ImmutableList.Builder<String>().add("A", "B").build();
        final List<String> case3 = new ImmutableList.Builder<String>().add("A", "B", "C").build();
        // test with standard Java
        assertEquals("A", joinListGrammaticallyWithJava(case1));
        assertEquals("A and B", joinListGrammaticallyWithJava(case2));
        assertEquals("A, B, and C", joinListGrammaticallyWithJava(case3));
        // test with guava
        assertEquals("A", joinListGrammaticallyWithGuava(case1));
        assertEquals("A and B", joinListGrammaticallyWithGuava(case2));
        assertEquals("A, B, and C", joinListGrammaticallyWithGuava(case3));
    }

    private String joinListGrammaticallyWithJava(final List<String> list) {
        return list.size() > 1
                ? String.join(", ", list.subList(0, list.size() - 1))
                    .concat(String.format("%s and ", list.size() > 2 ? "," : ""))
                    .concat(list.get(list.size() - 1))
                : list.get(0);
    }

    private String joinListGrammaticallyWithGuava(final List<String> list) {
        return list.size() > 1
                ? Joiner.on(", ").join(list.subList(0, list.size() - 1))
                    .concat(String.format("%s and ", list.size() > 2 ? "," : ""))
                    .concat(list.get(list.size() - 1))
                : list.get(0);
    }

}
2
Abtin Gramian

Je ne connais pas de menuisier Apache String pouvant prendre en charge l'ajout de and dans la chaîne jointe.

Voici un code non testé qui fera ce que vous avez demandé:

public static String join(String separator, List<String> mList, boolean includeAndInText) {
    StringBuilder sb = new StringBuilder();
    int count = 0;

    for (String m: mList) {
        if (includeAndInText && (count + 1 != mList.size())) {
            sb.append (" and ");
        }

        sb.append(m);
        count++;
        if (count < mList.size()) {
            sp.append(separator);
        }       
    }

    return sb.toString();
}
0
Buhake Sindi