最近我偶然发现需要将值列表拆分为正数和负数列表。然而,不是一个列表是正的,一个是负的,但一旦符号改变(忽略 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/