gpt4 book ai didi

Java 流 : is there a way to iterate taking two elements a time instead of one?

转载 作者:IT老高 更新时间:2023-10-28 21:01:00 27 4
gpt4 key购买 nike

假设我们有这个流

Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j");

我想在 map 中保存第一个以“err”开头的相邻字符串对。

我想到的是这样的

Map<String, String> map = new HashMap<>();

Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.reduce((acc, next) -> {
if (acc.startsWith("err"))
map.put(acc,next);
if (next.startsWith("err"))
return next;
else
return "";
});

但我对它并不完全满意,主要有两个原因

  1. 我在“滥用”reduce 函数。在 Stream API 中,每个函数都有其明确、明确的用途:max 应该计算最大值,filter 应该根据条件过滤,reduce 应该产生一个增量累加值等等。
  2. 这样做会阻止我使用 Streams 强大的机制:如果我想将搜索限制在前两个结果中怎么办?

这里我使用了 reduce 因为(据我所知)它是唯一可以让您比较几个值的函数,您可以以某种方式返回类似于“当前值”的值,并且“下一个值(value)”概念。

有没有更直接的方法?允许您在每次迭代中考虑多个值来迭代流的东西?

编辑

我正在考虑的是某种机制,在给定当前元素的情况下,它允许您为每次迭代定义要考虑的“元素窗口”。

类似

<R> Stream<R> mapMoreThanOne(
int elementsBeforeCurrent,
int elementsAfterCurrent,
Function<List<? super T>, ? extends R> mapper);

而不是

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

这将是对当前 API 的强大“升级”。

编辑2

我感谢人们提出解决方案的努力,但问题不在于算法本身。有不同的方法可以通过将流、索引、临时变量放在一起来存储以前的值来实现我的目标......但我想知道 Stream API 中是否有一些方法是为处理当前元素以外的元素而设计的在不破坏“流范式”的情况下。像这样的

List<String> list =
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.filterFunctionImWonderingIfExist(/*filters couples of elements*/)
.limit(2)
.collect(Collectors.toList());

鉴于答案,我认为没有“清晰快捷”的解决方案,除非使用 StreamEx 库

最佳答案

您可以构建自定义 Collector完成这项任务。

Map<String, String> map = 
Stream.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.collect(MappingErrors.collector());

与:

private static final class MappingErrors {

private Map<String, String> map = new HashMap<>();

private String first, second;

public void accept(String str) {
first = second;
second = str;
if (first != null && first.startsWith("err")) {
map.put(first, second);
}
}

public MappingErrors combine(MappingErrors other) {
throw new UnsupportedOperationException("Parallel Stream not supported");
}

public Map<String, String> finish() {
return map;
}

public static Collector<String, ?, Map<String, String>> collector() {
return Collector.of(MappingErrors::new, MappingErrors::accept, MappingErrors::combine, MappingErrors::finish);
}

}

在这个收集器中,保留了两个正在运行的元素。每次接受 String 时,都会更新它们,如果第一个以 "err" 开头,则将这两个元素添加到 map 中。


另一种解决方案是使用 StreamEx提供 pairMap 的库将给定函数应用于此流的每个相邻元素对的方法。在下面的代码中,如果第一个元素以 "err" 开头,则操作返回由该对的第一个和第二个元素组成的 String 数组,否则返回 nullnull 元素被过滤掉,Stream 被收集到一个 map 中。

Map<String, String> map = 
StreamEx.of("a", "b", "err1", "c", "d", "err2", "e", "f", "g", "h", "err3", "i", "j")
.pairMap((s1, s2) -> s1.startsWith("err") ? new String[] { s1, s2 } : null)
.nonNull()
.toMap(a -> a[0], a -> a[1]);

System.out.println(map);

关于Java 流 : is there a way to iterate taking two elements a time instead of one?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34086461/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com