我有一些0s内部数字列表.由于0在我的情况下意味着无效的度量,我需要0使用我在前面的位置中找到的第一个非0元素来更改值元素.
例如列表
45 55 0 0 46 0 39 0 0 0
Run Code Online (Sandbox Code Playgroud)
必须成为
45 55 55 55 46 46 39 39 39 39
Run Code Online (Sandbox Code Playgroud)
这是使用经典的实现 for each
int lastNonZeroVal = 0;
for (MntrRoastDVO vo : res) {
if (vo.getValColor() > 0) {
lastNonZeroVal = vo.getValColor();
} else {
vo.setValColor(lastNonZeroVal);
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法用Java Streams和Lambda函数实现它?
因为我知道我不能在foreach lambda中更改流的源,实际上列表是对象列表,我不会更改列表的元素,但我只是分配新值.
这是我的第一个解决方案
int lastNonZeroVal = 1;
resutl.stream().forEach(vo -> {
if(vo.getValColor()>0){
lastNonZeroVal=vo.getValColor();
}else{
vo.setValColor(lastNonZeroVal);
}
});
Run Code Online (Sandbox Code Playgroud)
但我也在这里读到
最好将lambdas传递给流操作完全没有副作用.也就是说,它们不会在执行期间改变任何基于堆的状态或执行任何I/O.
这让我很担心
数据是分区的,不能保证在处理给定元素时,已经处理了该元素之前的所有元素.
这个解决方案是否会产生无效结果,可能是当列表中的元素数量很高时??如果我不使用活动parallelStream()?
最好将lambdas传递给流操作完全没有副作用.也就是说,它们不会在执行期间改变任何基于堆的状态或执行任何I/O.
您的解决方案实际上有副作用,它会将您的源列表更改为资源列表.为避免这种情况,您需要map运算符并将流转换为Collection.因为您无法访问前一个元素,所以必须将状态存储在最终字段外部.出于简洁的原因,我使用了Integer而不是你的对象:
List<Integer> sourceList = Arrays.asList(45, 55, 0, 0, 46, 0, 39, 0, 0, 0);
final Integer[] lastNonZero = new Integer[1]; // stream has no state, so we need a final field to store it
List<Integer> resultList = sourceList.stream()
.peek(integer -> {
if (integer != 0) {
lastNonZero[0] = integer;
}
})
.map(integer -> lastNonZero[0])
.collect(Collectors.toList());
System.out.println(sourceList); // still the same
System.out.println(resultList); // prints [45, 55, 55, 55, 46, 46, 39, 39, 39, 39]
Run Code Online (Sandbox Code Playgroud)
除非您需要一些额外的操作,如过滤器,其他地图操作或排序,否则使用流来解决您的问题不是最佳解决方案.
有一种方法可以仅使用流函数来做到这一点,尽管在我看来它并不是特别干净。如果当前条目为零,您可以创建自己的收集器以默认为列表中的最后一个条目。像这样的东西:
void AddOrLast(List<Integer> list, Integer value) {
Integer toAdd = 0;
if (value != 0) {
toAdd = value;
} else {
if (!list.isEmpty()) {
toAdd = list.get(list.size() - 1);
}
}
list.add(toAdd);
}
@Test
public void name() {
List<Integer> nums = Arrays.asList(45, 55, 0, 0, 46, 0, 39, 0, 0, 0);
Collector<Integer, ArrayList<Integer>, List<Integer>> nonZeroRepeatCollector =
Collector.of(
ArrayList::new,
this::AddOrLast,
(list1, list2) -> { list1.addAll(list2); return list1; },
(x) -> x);
List<Integer> collect = nums.stream().collect(nonZeroRepeatCollector);
System.out.println(collect);
// OUT: [45, 55, 55, 55, 46, 46, 39, 39, 39, 39]
}
Run Code Online (Sandbox Code Playgroud)
AddOrLast如果非零,该方法将添加当前值,否则添加我们正在构建的数组中的最后一个条目。
使用nonZeroRepeatCollector供应商、累加器、组合器、整理器模式。
您可以修改流内对象的状态。但您无法修改数据源状态。
该问题与经典迭代中的问题相同。
用于forEachOrdered()执行
如果流具有定义的遇到顺序,则按流的遇到顺序对该流的每个元素执行操作
如果你打电话
result.stream.forEachOrdered(...)
Run Code Online (Sandbox Code Playgroud)
所有元素将按顺序依次处理。
对于顺序流forEach似乎尊重顺序。
| 归档时间: |
|
| 查看次数: |
10880 次 |
| 最近记录: |