处理时流 API 修改列表
Stream API modify list while processing
我有一个 Stream<List<Integer>>
,我收到但无法控制生成 api。列表最多有 4 个元素。但有些元素少于 4 个但保证至少有一个。我需要修改并向列表中添加零以使所有列表具有相同的大小 = 4.
举个例子,实际上我没有列表。
List<List<Integer>> myList = List.of(List.of(1,2,3,4),
List.of(7,5),
List.of(2,9),
List.of(1));
Stream<List<Integer>> myStream = myList().stream();
我需要进一步处理长度为 4 的相同大小的列表,因此上面的列表应该类似于 [1,2,3,4],[7,5,0,0],[2,9,0,0],[1,0,0,0]
。最好我不想在中间结果列表中收集流。我天真的方法行不通,因为 list.add returns 布尔值不是列表,也没有考虑要添加多少个零。
myStream.map(list -> list.size() == 4 ? list : list.add(0)
如何达到想要的效果?
如果可能我想避免:
List<List<Integer> collected = myStream.collect(toList());
for(List<Integer> temp : collected){
if(temp.size() < 4){
for(int i= 0; i < 4 - temp.size(); i++){
temp.add(0);
}
}
}
myStream = collected.stream();
流 API 与修改任何东西无关,而是与转换有关(例如,将一个对象映射到另一个对象)。从这个意义上说,您希望流只是神奇地增加零,或者转换您的输入列表,例如[7, 5]
进入一个包含 [7, 5, 0, 0]
的全新 list/streamable 概念。一旦你开始修改你的输入,流就会产生无穷无尽的缺陷、警告和错误——这不是它们的目的,你现在是在用一把锤子给你的吐司抹黄油,这可能是可能的,但不是一个好主意想法 - 去拿你的黄油刀。
幸运的是,您的工作描述从根本上讲并不是关于修改这些输入,所以这不是一个亮点。
实现这个目标的方法有很多。选择你的毒药:
制作一个class来表示填充列表的概念。
myList.stream().map(list -> new PaddedList(list, 0, 4))....
是你所需要的,但是你必须自己编写PaddedList,这会花费一些精力。它看起来像这样,但我遗漏了很多:
public class PaddedList<T> extends AbstractList<T> {
private final List<T> source;
private final int padSize;
private final T padElem;
public T get(int idx) {
return (idx < 0 || idx >= padSize || source.size() > idx) ?
source.get(idx) : padElem;
}
public int size() {
return Math.max(padSize, source.size());
}
}
map
您输入的列表以进行调整
myList.stream().map(list -> {
if (list.size() >= 4) return list;
var out = new ArrayList<Integer>(list);
while (out.size() < 4) out.add(0);
return out;
})....
那不过我们去打高尔夫球吧
myList.stream().map(list -> Arrays.asList(list.toArray(new Integer[4])))....
还有很多很多选择
特别是如果您不一定需要以列表形式输出(例如,如果它可以是可迭代的形式,或作为流)。
但是,流 API 中没有 'pad it up' 等效项。有一个 pad-it-down(例如 .limit(4)
),但不是相反的。
我有一个 Stream<List<Integer>>
,我收到但无法控制生成 api。列表最多有 4 个元素。但有些元素少于 4 个但保证至少有一个。我需要修改并向列表中添加零以使所有列表具有相同的大小 = 4.
举个例子,实际上我没有列表。
List<List<Integer>> myList = List.of(List.of(1,2,3,4),
List.of(7,5),
List.of(2,9),
List.of(1));
Stream<List<Integer>> myStream = myList().stream();
我需要进一步处理长度为 4 的相同大小的列表,因此上面的列表应该类似于 [1,2,3,4],[7,5,0,0],[2,9,0,0],[1,0,0,0]
。最好我不想在中间结果列表中收集流。我天真的方法行不通,因为 list.add returns 布尔值不是列表,也没有考虑要添加多少个零。
myStream.map(list -> list.size() == 4 ? list : list.add(0)
如何达到想要的效果?
如果可能我想避免:
List<List<Integer> collected = myStream.collect(toList());
for(List<Integer> temp : collected){
if(temp.size() < 4){
for(int i= 0; i < 4 - temp.size(); i++){
temp.add(0);
}
}
}
myStream = collected.stream();
流 API 与修改任何东西无关,而是与转换有关(例如,将一个对象映射到另一个对象)。从这个意义上说,您希望流只是神奇地增加零,或者转换您的输入列表,例如[7, 5]
进入一个包含 [7, 5, 0, 0]
的全新 list/streamable 概念。一旦你开始修改你的输入,流就会产生无穷无尽的缺陷、警告和错误——这不是它们的目的,你现在是在用一把锤子给你的吐司抹黄油,这可能是可能的,但不是一个好主意想法 - 去拿你的黄油刀。
幸运的是,您的工作描述从根本上讲并不是关于修改这些输入,所以这不是一个亮点。
实现这个目标的方法有很多。选择你的毒药:
制作一个class来表示填充列表的概念。
myList.stream().map(list -> new PaddedList(list, 0, 4))....
是你所需要的,但是你必须自己编写PaddedList,这会花费一些精力。它看起来像这样,但我遗漏了很多:
public class PaddedList<T> extends AbstractList<T> {
private final List<T> source;
private final int padSize;
private final T padElem;
public T get(int idx) {
return (idx < 0 || idx >= padSize || source.size() > idx) ?
source.get(idx) : padElem;
}
public int size() {
return Math.max(padSize, source.size());
}
}
map
您输入的列表以进行调整
myList.stream().map(list -> {
if (list.size() >= 4) return list;
var out = new ArrayList<Integer>(list);
while (out.size() < 4) out.add(0);
return out;
})....
那不过我们去打高尔夫球吧
myList.stream().map(list -> Arrays.asList(list.toArray(new Integer[4])))....
还有很多很多选择
特别是如果您不一定需要以列表形式输出(例如,如果它可以是可迭代的形式,或作为流)。
但是,流 API 中没有 'pad it up' 等效项。有一个 pad-it-down(例如 .limit(4)
),但不是相反的。