java - 使用流在符号更改时拆分列表或数组

标签 java list split java-8 java-stream

最近我偶然发现需要将值列表拆分为正数和负数列表。然而,不是一个列表是正的,一个是负的,但一旦符号改变(忽略 0 值)基本上开始一个新列表;

例子:

valuesInList = [-1, -3, -5, -120, 0, 15, 24, 42, 13, -15, -24, -42, 1, 2, 3]
splitList = [[-1, -3, -5, -120], [15, 24, 42, 13], [-15, -24, -42], [1, 2, 3]]

我编写了有效的代码,但我对此并不满意:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        Byte[] values = new Byte[]{-1, -3, -5, -120, 0, 15, 24, 42, 13, -15, -24, -42, 1, 2, 3}; //0 -> ignore
        List<Byte> valuesInList = Arrays.asList(values);
        System.out.println("valuesInList = " + valuesInList);
        int firstNotZero = valuesInList.stream().filter(b -> b != 0).collect(Collectors.toList()).get(0);
        boolean currentlyLookingForPositive = firstNotZero > 0;

        List<List<Byte>> splitList = new ArrayList<>();

        int index = 0;

        while (index < valuesInList.size()) {
            List<Byte> collection = new ArrayList<>();
            while (currentlyLookingForPositive && index < valuesInList.size()) {
                byte current = valuesInList.get(index);
                if (current > 0) {
                    collection.add(current);
                    index++;
                }
                else
                    currentlyLookingForPositive = false;
                if (current == 0)
                    index++;
            }
            if (!collection.isEmpty())
                splitList.add(collection);

            collection = new ArrayList<>();
            while (!currentlyLookingForPositive && index < valuesInList.size()) {
                byte current = valuesInList.get(index);
                if (current < 0) {
                    collection.add(current);
                    index++;
                }
                else
                    currentlyLookingForPositive = true;
            }
            if (!collection.isEmpty())
                splitList.add(collection);
        }

        System.out.println("splitList = " + splitList);
    }

}

我认为原因很明显:重复代码的主要部分。但是我不知道如何将这种方式导出到一种方法以使代码更清晰。
此外,既然我看到了流的巨大潜力,我想知道是否有一种方便的方法来使用 Java 8 Streams 或使用其他 Java 8 功能来编写这个批量代码,以至少在一个方法中运行部分代码。

编辑:这个问题被标记为可能与 Group sequences of values 重复.尽管标题可能会有所不同,但问题(至少从我的角度来看)并不是重复的。链接的要求按升序值分组,而我的要求按符号(正/负)分组。

最佳答案

一个快速而肮脏的解决方案:

List<List<Integer>> result = Arrays.asList(-1, -3, -5, -120, 0, 15, 24, 42, 13, -15, -24, -42, 1, 2, 3)
            .stream()
            .collect(Collector.of(
                    () -> {
                        List<List<Integer>> list = new ArrayList<>();
                        list.add(new ArrayList<>());
                        return list;
                    },
                    (list, x) -> {

                        if (x == 0) {
                            return;
                        }

                        if (list.size() == 0) {
                            list.get(0).add(x);
                        } else {
                            List<Integer> lastInner = list.get(list.size() - 1);
                            if (lastInner.size() > 0) {
                                int elem = lastInner.get(0);
                                if (elem >>> 31 == x >>> 31) {
                                    lastInner.add(x);
                                } else {
                                    List<Integer> oneMore = new ArrayList<>();
                                    oneMore.add(x);
                                    list.add(oneMore);
                                }
                            } else {
                                lastInner.add(x);
                            }

                        }

                    }, (left, right) -> {

                        throw new RuntimeException("Not for aprallel");
                    }));

    System.out.println(result);

我仍在考虑是否可以进行并行处理(自定义收集器的组合器)。此外,将其提取到返回此收集器以供进一步重新使用的方法可能会更好。将更新

编辑

或者如果没有StreamEx:

List<Integer> input = Arrays.asList(-1, -3, -5, -120, 0, 15, 24, 42, 13, -15, -24, -42, 1, 2, 3);
    List<Integer> filtered = input.stream().filter(x -> x != 0).collect(Collectors.toList());

    int[] indexes = IntStream.range(0, filtered.size() - 2)
            .filter(x -> x == 0 || x == filtered.size() || filtered.get(x) >>> 31 != filtered.get(x + 1) >>> 31)
            .map(x -> x + 1)
            .toArray();

    List<List<Integer>> result = IntStream.range(0, indexes.length - 1)
            .mapToObj(x -> filtered.subList(indexes[x], indexes[x + 1]))
            .collect(Collectors.toList());

    System.out.println(result);

关于java - 使用流在符号更改时拆分列表或数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45728437/

相关文章:

java - 使 Sonar 覆盖 "don' t 声明 'throws Exception'“仅在单元测试类中

c# - 如何使用 List 压缩一堆 IF 语句——这可能吗?

json - 使用 lift-json 是否有一种简单的方法来提取和遍历列表?

c# - Dictionary<string, List<IRp>> 问题,覆盖数据

java - Hibernate语法错误: Expected DOT

java - 将文本文件读入 Stack 并按相反顺序打印出元素

java - 打印应在命令行中提供大小的数组

c# - 使用 Linq 在值之间添加逗号

javascript - 我们如何使用以正则表达式开头的字符串 (/^myString/g)

Php在不同字符上拆分字符串