通过整理合并两个流
Combine two streams with collation
我需要以高效灵活的方式完成一些 Matrix 工作,并希望我可以使用流和 lambda 练习我的 Java 8,甚至可能从中获得自由并行性。我纠结的一点是如何对两个流执行操作,将结果放入第三个流中。
考虑简单的机制:
static final List<String> a = Arrays.asList("A", "A", "A");
static final List<String> b = Arrays.asList("B", "B", "B");
public void withoutStreams() {
// The boring old way.
List<String> c = new ArrayList<>();
for (Iterator<String> ai = a.iterator(), bi = b.iterator(); ai.hasNext() && bi.hasNext();) {
c.add(ai.next() + bi.next());
}
System.out.println(c);
}
工作正常,但我想使用 Streams。
private void withStreams() {
List<String> c = new ArrayList<>();
combine(a.stream(), b.stream(), c, (String x, String y) -> x + y);
}
private void combine(Stream<String> a, Stream<String> b, List<String> c, BinaryOperator<String> op) {
// What can I do here to make it happen?
}
我完全希望我们将使用某种形式的 Consumer
填充 c
,但额外的荣誉是想出某种方式来引用矩阵的特定单元格而不是使用 (row ,col) 请记住,单元格将是不可变的。
您可以使用 IntStream
class 模拟索引,然后 .mapToObj
连接 a
和 b
中对应的索引对象:
List<String> list = IntStream.range(0, Math.max(a.size(), b.size()))
.mapToObj(i -> a.get(i) + b.get(i))
.collect(Collectors.toList());
应用到您的方法后,将如下所示:
private void combine(List<String> a, List<String> b, List<String> c, BinaryOperator<String> op) {
c = IntStream.range(0, Math.max(a.size(), b.size()))
.mapToObj(i -> op.apply(a.get(i), b.get(i)))
.collect(Collectors.toList());
}
但是,如果您不想更改方法的签名,here is a solution which works for all possible combinations of infinite and finite streams:
private void combine(Stream<String> a, Stream<String> b, List<String> c, BinaryOperator<String> op) {
Iterator<String> i1 = a.iterator();
Iterator<String> i2 = b.iterator();
Iterable<String> i = () -> new Iterator<String>() {
public boolean hasNext() {
return i1.hasNext() && i2.hasNext();
}
public String next() {
return op.apply(i1.next(), i2.next());
}
};
c = StreamSupport.stream(i.spliterator(), false).collect(Collectors.toList());
}
函数式编程风格,使用递归(无循环):
static Stream<String> combine(List<String> a, List<String> b) {
if(a.isEmpty() || b.isEmpty()) {
return Stream.empty();
}
return Stream.concat(
Stream.of(a.get(0) + b.get(0)),
combine(a.stream().skip(1).collect(Collectors.toList()),
b.stream().skip(1).collect(Collectors.toList()))
);
}
加:我给kocko的回答投赞成票,我的回答是为了好玩。
我需要以高效灵活的方式完成一些 Matrix 工作,并希望我可以使用流和 lambda 练习我的 Java 8,甚至可能从中获得自由并行性。我纠结的一点是如何对两个流执行操作,将结果放入第三个流中。
考虑简单的机制:
static final List<String> a = Arrays.asList("A", "A", "A");
static final List<String> b = Arrays.asList("B", "B", "B");
public void withoutStreams() {
// The boring old way.
List<String> c = new ArrayList<>();
for (Iterator<String> ai = a.iterator(), bi = b.iterator(); ai.hasNext() && bi.hasNext();) {
c.add(ai.next() + bi.next());
}
System.out.println(c);
}
工作正常,但我想使用 Streams。
private void withStreams() {
List<String> c = new ArrayList<>();
combine(a.stream(), b.stream(), c, (String x, String y) -> x + y);
}
private void combine(Stream<String> a, Stream<String> b, List<String> c, BinaryOperator<String> op) {
// What can I do here to make it happen?
}
我完全希望我们将使用某种形式的 Consumer
填充 c
,但额外的荣誉是想出某种方式来引用矩阵的特定单元格而不是使用 (row ,col) 请记住,单元格将是不可变的。
您可以使用 IntStream
class 模拟索引,然后 .mapToObj
连接 a
和 b
中对应的索引对象:
List<String> list = IntStream.range(0, Math.max(a.size(), b.size()))
.mapToObj(i -> a.get(i) + b.get(i))
.collect(Collectors.toList());
应用到您的方法后,将如下所示:
private void combine(List<String> a, List<String> b, List<String> c, BinaryOperator<String> op) {
c = IntStream.range(0, Math.max(a.size(), b.size()))
.mapToObj(i -> op.apply(a.get(i), b.get(i)))
.collect(Collectors.toList());
}
但是,如果您不想更改方法的签名,here is a solution which works for all possible combinations of infinite and finite streams:
private void combine(Stream<String> a, Stream<String> b, List<String> c, BinaryOperator<String> op) {
Iterator<String> i1 = a.iterator();
Iterator<String> i2 = b.iterator();
Iterable<String> i = () -> new Iterator<String>() {
public boolean hasNext() {
return i1.hasNext() && i2.hasNext();
}
public String next() {
return op.apply(i1.next(), i2.next());
}
};
c = StreamSupport.stream(i.spliterator(), false).collect(Collectors.toList());
}
函数式编程风格,使用递归(无循环):
static Stream<String> combine(List<String> a, List<String> b) {
if(a.isEmpty() || b.isEmpty()) {
return Stream.empty();
}
return Stream.concat(
Stream.of(a.get(0) + b.get(0)),
combine(a.stream().skip(1).collect(Collectors.toList()),
b.stream().skip(1).collect(Collectors.toList()))
);
}
加:我给kocko的回答投赞成票,我的回答是为了好玩。