简体   繁体   English

在Java 8中使用flatmap编写流

[英]Composing streams with flatmap in Java 8

Let's consider I have the following class: 我们考虑一下我有以下课程:

class A {
   int i, j, k;

   public A(int i, int j, int k) {
     this.i = i; this.j = j; this.k = k;
   }
}

where i , j , k have a known range: r_i , r_j , r_k . 其中ijk具有已知范围: r_ir_jr_k Now I want to to generate all possible instances of A in this range. 现在我想在此范围内生成A所有可能实例。 I could come up with something like: 我可以想出类似的东西:

Stream.iterate(0, n -> ++n).limit(r_i)
.flatMap(i -> Stream.iterate(0, n -> ++n).limit(r_j)
.flatMap(j -> Stream.iterate(0, n -> ++n).limit(r_k)
.map(k -> new A(i, j, k)))).collect(Collectors.toList())

First, it's too verbose. 首先,它太冗长了。 Is there a way to shorten it? 有没有办法缩短它? In particular I couldn't find a range on Stream . 特别是我在Stream上找不到range Second, the compiler cannot determine the type of the returned type. 其次,编译器无法确定返回类型的类型。 It considers it as List<Object> instead of the expected List<A> . 它将其视为List<Object>而不是预期的List<A> How can I fix that? 我该如何解决这个问题?

One way of using range is to perform a boxing conversion right afterwards: 使用range一种方法是在之后执行拳击转换:

List<A> list=IntStream.range(0, r_i).boxed()
  .flatMap(i -> IntStream.range(0, r_j).boxed()
    .flatMap(j -> IntStream.range(0, r_k)
      .mapToObj(k -> new A(i, j, k)))).collect(Collectors.toList());

It's not the most beautiful code but IntStream.range(0, max).boxed() is still better than Stream.iterate(0, n -> n+1).limit(max) 它不是最漂亮的代码,但IntStream.range(0, max).boxed()仍然比Stream.iterate(0, n -> n+1).limit(max) ...


One alternative is to use a real flattening operation rather than nested operations: 一种替代方法是使用实​​际展平操作而不是嵌套操作:

List<A> list=IntStream.range(0, r_i).boxed()
  .flatMap(i  -> IntStream.range(0, r_j).mapToObj(j -> new int[]{i,j}))
  .flatMap(ij -> IntStream.range(0, r_k).mapToObj(k -> new A(ij[0], ij[1], k)))
  .collect(Collectors.toList());

The main drawback I see is that it suffers from the absence of an IntPair or Tuple<int,int> type. 我看到的主要缺点是它缺少IntPairTuple<int,int>类型。 So it uses an array as a work-around. 所以它使用数组作为解决方法。

if it's ok to have mutable variable, you could get the List of class A like this.... 如果有可变变量,你可以像这样获得A类的List ....

List<A> newCollect = new ArrayList<>();
IntStream.range(0, r_i).forEach(
    i -> IntStream.range(0, r_j).forEach(
        j -> IntStream.range(0, r_k).forEach(
            k -> newCollect.add(new A(i, j, k))
        )
    )
);

or you can make List of List of List of A, then flatMap twice like this... 或者你可以制作A列表列表,然后像这样两次flatMap ...

List<A> newCollect2 = IntStream.range(0, r_i).mapToObj(
    i -> IntStream.range(0, r_j).mapToObj(
        j -> IntStream.range(0, r_k).mapToObj(
            k -> new A(i, j, k)
        ).collect(Collectors.toList())
    ).collect(Collectors.toList())
)
.flatMap(a -> a.stream())
.flatMap(a -> a.stream())
.collect(Collectors.toList());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM