使用 Java 8 Streams 减少字符串列表,仅将前缀添加到最后一个元素

Reduce a list of string add prefix only to last element using Java 8 Streams

如何使用 Java 8 Streams 减少或收集以逗号分隔并仅在最后一个元素前加上 "and" 前缀的字符串列表?

例如。

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

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

System.out.println(result);

此语句打印 => 汤姆、特里、约翰、凯文、史蒂夫。但我想将列表打印为 tom、terry、john、kevin 和 steve。

流并没有使这变得更容易。你也可以使用 String::replaceAll:

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

System.out.println(result);

输出:

tom, terry, john, kevin and steve

两种解决方案。

笨手笨脚,居然取子列表:

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

使用class移动一位:

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

注意:class 定义应该放在方法内部,就像上面一样。否则将需要 static(a, s) 的 lambda 可能是 SbS 中的一种方法。对并行性的支持留作 reader (a1, a1).

的练习

Stream API 没有提供实现此目的的标准方法。我的 StreamEx library which extends standard Stream API has a mapLast 方法在这里很有用。它只允许映射最后一个流元素,其他所有元素保持原样:

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

结果如下:

tom, terry, john, kevin, and steve

请注意,它在 "and" 之前添加了一个逗号,这是可以的(请参阅 Oxford Comma)。如果你不喜欢它(或者实际上使用另一种禁止这种标点符号的语言),那么它可以用稍微长一点的方式来实现:

StreamEx.of(ls)
        .mapLastOrElse(", "::concat, " and "::concat)
        .joining().substring(", ".length());