将逗号分隔的数字列表压缩到范围中

amr*_*_bd 9 java arrays range java-8 java-stream

我正在寻找一种聪明的方法来执行以下操作:

列出一个数字列表:

1,2,3,4,5,12,13,14,19

并将其压缩成一个字符串,如下所示:

1-5,12-14,19

使用以下规则:当范围中的数字计数为3或更多时,仅压缩到范围(即使用破折号).

即:1,2,4,5将导致:1,2,4,5和NOT:1-2,4-5

Hol*_*ger 10

现在我们已经看到了几个Stream变体,这里是非Stream变体用于比较:

private static StringBuilder appendRange(StringBuilder sb, int start, int previous) {
    sb.append(start);
    if(start!=previous) sb.append(previous-start>1? " - ": ", ").append(previous);
    return sb;
}
Run Code Online (Sandbox Code Playgroud)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 12, 13, 14, 19);
StringBuilder sb = new StringBuilder();
int previous = list.get(0), start = previous;
for(int next: list.subList(1, list.size())) {
    if(previous+1 != next) {
        appendRange(sb, start, previous).append(", ");
        start = next;
    }
    previous = next;
}
String result = appendRange(sb, start, previous).toString();
Run Code Online (Sandbox Code Playgroud)

  • 这不是"需要使用java-8 stream()"的自然要求.您可以选择任何其他的,不完整的(例如与并行流不兼容),更复杂的基于流的解决方案.如果这是一个赋值,那么回答显示两个变量以证明此任务不适合使用Stream API可能很有用. (6认同)

Eug*_*ene 4

我只能考虑一个自定义收集器...显然,您可以创建一个返回此收集器的方法,并且在这种情况下代码将非常紧凑,前提是收集器通过静态工厂方法隐藏。

请注意,它combiner基本上什么也没做,不利于并行编码。我仍在尝试想出一个好方法来为其提供实现。

 List<String> result = IntStream.of(1, 2, 3, 4, 5, 12, 13, 14, 19)
            .boxed()
            .collect(Collector.of(
                    () -> {
                        List<List<Integer>> list = new ArrayList<>();
                        list.add(new ArrayList<>());
                        return list;
                    },
                    (list, x) -> {
                        List<Integer> inner = list.get(list.size() - 1);
                        if (inner.size() == 0) {
                            inner.add(x);
                        } else {
                            int lastElement = inner.get(inner.size() - 1);
                            if (lastElement == x - 1) {
                                inner.add(x);
                            } else {
                                List<Integer> oneMore = new ArrayList<>();
                                oneMore.add(x);
                                list.add(oneMore);
                            }
                        }
                    },
                    (left, right) -> {
                        throw new IllegalArgumentException("No parallel!");
                    },

                    list -> {

                        return list.stream()
                                .map(inner -> {
                                    if (inner.size() > 1) {
                                        return inner.get(0) + "-" + inner.get(inner.size() - 1);
                                    }
                                    return "" + inner.get(0);
                                }).collect(Collectors.toList());

                    }));

    System.out.println(result);
Run Code Online (Sandbox Code Playgroud)