是否可以使用Java 8流构造更简洁地表达以下逻辑:
public static Set<Pair> findSummingPairsLookAhead(int[] data, int sum){
Set<Pair> collected = new HashSet<>();
Set<Integer> lookaheads = new HashSet<>();
for(int i = 0; i < data.length; i++) {
int elem = data[i];
if(lookaheads.contains(elem)) {
collected.add(new Pair(elem, sum - elem));
}
lookaheads.add(sum - elem);
}
return collected;
}一些类似于Arrays.stream(data).forEach(...)的东西。
提前谢谢。
发布于 2017-09-29 09:31:24
涉及在迭代期间改变状态的算法不太适合流。但是,通常可以根据不显式改变任何中间状态的批量操作来重新考虑算法。
在您的示例中,任务是收集一组Pair(x, sum - x),其中sum - x在列表中出现在x之前。因此,我们可以首先构建一个数字到其在列表中第一次出现的索引的映射,然后使用该映射来过滤列表并构建一组配对:
Map<Integer, Integer> firstIdx = IntStream.range(0, data.length)
.boxed()
.collect(toMap(i -> data[i], i -> i, (a, b) -> a));
Set<Pair> result = IntStream.range(0, data.length)
.filter(i -> firstIdx.contains(sum - data[i]))
.filter(i -> firstIdx.get(sum - data[i]) < i)
.mapToObj(i -> new Pair(data[i], sum - data[i]))
.collect(toSet());您可以使用&&或getOrDefault来缩短这两个过滤器,如果您觉得这样做更清晰的话。
发布于 2017-09-29 05:00:39
值得一提的是,命令式实现可能是表达期望的最有效方式。但是如果你真的想用Java8Stream API实现同样的逻辑,你可以考虑使用.reduce()方法,例如
import org.apache.commons.lang3.tuple.Pair;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
final class SummingPairsLookAheadExample {
public static void main(String[] args) {
final int[] data = new int[]{1,2,3,4,5,6};
final int sum = 8;
final Set<Pair> pairs = Arrays.stream(data)
.boxed()
.parallel()
.reduce(
Pair.of(Collections.synchronizedSet(new HashSet<Pair>()), Collections.synchronizedSet(new HashSet<Integer>())),
(pair,el) -> doSumming(pair, el, sum),
(a,b) -> a
).getLeft();
System.out.println(pairs);
}
synchronized private static Pair<Set<Pair>, Set<Integer>> doSumming(Pair<Set<Pair>, Set<Integer>> pair, int el, int sum) {
if (pair.getRight().contains(el)) {
pair.getLeft().add(Pair.of(el, sum - el));
}
pair.getRight().add(sum - el);
return pair;
}
}输出
[(5,3), (6,2)].reduce()方法的第一个参数是累加器的初始值。此对象将被传递到每个迭代步骤。在我们的示例中,我们使用一对Set<Pair> (预期结果)和Set<Integer> (与示例中的变量lookaheads相同)。第二个参数是一个执行逻辑的lambda (BiFunction) (提取到一个单独的私有方法,以使代码更紧凑)。最后是二元运算符。它相当冗长,但它不依赖于任何副作用。@Eugene指出,我之前的例子在并行执行方面有问题,所以我更新了这个例子,以便在并行执行中也是安全的。如果你不并行运行它,你可以简单地从助手方法中删除synchronized关键字,并使用常规集而不是同步集作为累加器的初始值。
发布于 2017-09-29 12:45:47
您是否正在尝试获取等于指定sum的唯一Pairs
Arrays.stream(data).boxed()
.collect(Collectors.groupingBy(i -> i <= sum / 2 ? i : sum - i, toList())).values().stream()
.filter(e -> e.size() > 1 && (e.get(0) * 2 == sum || e.stream().anyMatch(i -> i == sum - e.get(0))))
.map(e -> Pair.of(sum - e.get(0), e.get(0)))
.collect(toList());返回具有唯一对的列表。如果需要,您可以将其更改为由toSet()设置。
https://stackoverflow.com/questions/46477789
复制相似问题