Join strings with different last delimiter

前端 未结 7 1134
感情败类
感情败类 2021-01-04 12:04

Using stream.collect(Collectors.joining(\", \")) I can easily join all the strings of my stream delimited by a comma. A possible result would be \"a, b, c

相关标签:
7条回答
  • 2021-01-04 12:45

    If they are already in a list, no stream is needed; simply join a sublist of all but the last element and concat the other delimiter and the final element:

    int last = list.size() - 1;
    String joined = String.join(" and ",
                        String.join(", ", list.subList(0, last)),
                        list.get(last));
    

    Here's a version that does the above using Collectors.collectingAndThen:

    stream.collect(Collectors.collectingAndThen(Collectors.toList(),
        joiningLastDelimiter(", ", " and ")));
    
    public static Function<List<String>, String> joiningLastDelimiter(
            String delimiter, String lastDelimiter) {
        return list -> {
                    int last = list.size() - 1;
                    if (last < 1) return String.join(delimiter, list);
                    return String.join(lastDelimiter,
                        String.join(delimiter, list.subList(0, last)),
                        list.get(last));
                };
    }
    

    This version can also handle the case where the stream is empty or only has one value. Thanks to Holger and Andreas for their suggestions which greatly improved this solution.

    I had suggested in a comment that the Oxford comma could be accomplished with this using ", " and ", and" as the delimiters, but that yields incorrect results of "a, and b" for two elements, so just for fun here's one that does Oxford commas correctly:

    stream.collect(Collectors.collectingAndThen(Collectors.toList(),
        joiningOxfordComma()));
    
    public static Function<List<String>, String> joiningOxfordComma() {
        return list -> {
                    int last = list.size() - 1;
                    if (last < 1) return String.join("", list);
                    if (last == 1) return String.join(" and ", list);
                    return String.join(", and ",
                        String.join(", ", list.subList(0, last)),
                        list.get(last));
                };
    }
    
    0 讨论(0)
  • 2021-01-04 12:46
        List<String> names = Arrays.asList("Thomas", "Pierre", "Yussef", "Rick");
        int length = names.size();
        String result = IntStream.range(0, length - 1).mapToObj(i -> {
            if (i == length - 2) {
                return names.get(i) + " and " + names.get(length - 1);
            } else {
                return names.get(i);
            }
        }).collect(Collectors.joining(", "));
    
    0 讨论(0)
  • 2021-01-04 12:47

    This is not a Streams-API solution but is pretty fast. Enjoy!

    public static final <E> String join(
        Iterable<E> objects, String separator, String lastSeparator) 
    {
        Objects.requireNonNull(objects);
    
        final String sep = separator == null ? "" : separator;
        final String lastSep = lastSeparator == null ? sep : lastSeparator;
    
        final StringBuilder builder = new StringBuilder();
    
        final Iterator<E> iterator = objects.iterator();
        while (iterator.hasNext()) {
            final E next = iterator.next();
            if (builder.length() > 0) {
                if (iterator.hasNext()) {
                    builder.append(sep);
                }
                else {
                    builder.append(lastSep);
                }
            }
            builder.append(next);
        }
    
        return builder.toString();
    }
    
    0 讨论(0)
  • 2021-01-04 12:48

    If you are looking for old Java solution, using Guava libraries would be easy.

        List<String> values = Arrays.asList("a", "b", "c");
        String output = Joiner.on(",").join(values);
        output = output.substring(0, output.lastIndexOf(","))+" and "+values.get(values.size()-1);
        System.out.println(output);//a,b and c
    
    0 讨论(0)
  • 2021-01-04 12:48
    String str = "a , b , c , d";
    String what_you_want = str.substring(0, str.lastIndexOf(","))
            + str.substring(str.lastIndexOf(",")).replace(",", "and");
    
    // what_you_want is : a , b , c and d
    
    0 讨论(0)
  • 2021-01-04 12:51

    If you're fine with "a, b, and c", then it's possible to use mapLast method of my StreamEx library which extends standard Stream API with additional operations:

    String result = StreamEx.of("a", "b", "c")
                            .mapLast("and "::concat)
                            .joining(", "); // "a, b, and c"
    

    The mapLast method applies given mapping to the last stream element keeping others unchanged. I even have similar unit-test.

    0 讨论(0)
提交回复
热议问题