Сократить список префиксов добавления строки только до последнего элемента, используя потоки Java 8

Как я могу уменьшить или собрать список строк, разделенных запятыми и с префиксом "и" только до последнего элемента, использующего потоки Java 8?

например.

List<String> ls = Arrays.asList("tom","terry","john","kevin","steve");

String result = ls.stream().map(String::toString)
                .collect(Collectors.joining(", "));

System.out.println(result);

Это утверждение печатает => Том, Терри, Джон, Кевин, Стив. Но я хотел напечатать список как Том, Терри, Джон, Кевин и Стив.

3 ответа

Решение

Два решения.

Коряво, взяв подсписок на самом деле:

    String result = ls.stream()
            .limit(ls.size() - 1)
            .collect(Collectors.joining(", ")) + " and " + ls.get(ls.size() - 1);

Использование класса для перемещения на одно место:

    class SbS {
        StringBuilder sb = new StringBuilder();
        String s = "";

        @Override
        public String toString() {
            return sb + (s.empty() ? "" : " and " + s);
        }
    }
    result = ls.stream()
            .collect(SbS::new,
                (a, s) -> {
                    a.sb.append(a.sb.length() == 0 ? "" : ", ").append(a.s); a.s = s;
                },
                (a1, a2) -> {}).toString();

Обратите внимание: определение класса должно быть помещено внутри метода, как указано выше. Иначе static будет необходимо. Лямбда для (a, s) может быть методом в SbS. Поддержка параллелизма оставлена ​​в качестве упражнения для читателя (a1, a1),

Потоки не делают это проще. Вы могли бы также использовать String::replaceAll:

String input = "tom, terry, john, kevin, steve";
String result = input.replaceAll(", (\\w+)$", " and $1");

System.out.println(result);

Выход:

tom, terry, john, kevin and steve

Stream API не предоставляет стандартного способа достижения этого. Моя библиотека StreamEx, которая расширяет стандартный Stream API, имеет mapLast метод, который полезен здесь. Это позволяет отображать только последний элемент потока, оставляя все остальное как есть:

System.out.println(StreamEx.of(ls).mapLast("and "::concat).joining(", "));

Результат следующий:

tom, terry, john, kevin, and steve

Обратите внимание, что он добавляет запятую перед "и", что нормально (см. Оксфордская запятая). Если вам это не нравится (или на самом деле используется другой язык, который запрещает такие знаки препинания), то это может быть достигнуто немного более длинным способом:

StreamEx.of(ls)
        .mapLastOrElse(", "::concat, " and "::concat)
        .joining().substring(", ".length());
Другие вопросы по тегам