如何使用Java 8 Streams以特定方式实现zip?

时间:2016-01-17 12:57:07

标签: java java-8 java-stream

我试图弄清楚如何使用Streams API来实现一个zip函数,该函数将无限数量的int []作为参数;从每个元素中取出第i个元素;把它们放在一个元组中(显然需要一个自定义元组对象 - 我有)并返回一个元组列表(即List)。

基本上,对于:

[ Tuple(1, 4), Tuple(2, 5), Tuple(3, 6) ]

建议的方法应该返回: java.util.List<Tuple> /** * Return a list of tuples, where each tuple contains the i-th element * from each of the argument sequences. The returned list is * truncated in length to the length of the shortest argument sequence. * * @param args the array of ints to be wrapped in {@link Tuple}s * @return a list of tuples */ public static List<Tuple> zip(int[]... args) { List<Tuple> retVal = new ArrayList<>(); // Find the array with the minimum size int minLength = Arrays.stream(args).map(i -> new Integer(i.length)).min((a, b) -> a.compareTo(b)).get(); for(int i = 0;i < minLength;i++) { Tuple.Builder builder = Tuple.builder(); for(int[] ia : args) { builder.add(ia[i]); } retVal.add(builder.build()); } return retVal; }

这是一个功能,可以完成我在&#34;正常&#34;中所做的事情。方式:

SubClass

1 个答案:

答案 0 :(得分:4)

解决方案是在索引上创建Stream,并使用mapToObj将每个int映射到Tuple。此外,由于您已经拥有Builder个对象,我们可以利用它来收集元素。

假设我们添加一个方法Tuple.Builder.addAll(Tuple.Builder other),其目的是将一个构建器添加到另一个构建器,我们可以使用以下代码:

public static List<Tuple> zip(int[]... args) {
    // Find the array with the minimum size
    int minLength = Arrays.stream(args).mapToInt(i -> i.length).min().orElse(0);

    return IntStream.range(0, minLength)
                    .mapToObj(i -> 
                       Arrays.stream(args)
                             .mapToInt(ia -> ia[i])
                             .collect(Tuple::builder, Tuple.Builder::add, Tuple.Builder::addAll)
                             .build()
                    ).collect(Collectors.toList());
}

(如果您不想支持并行执行,则可以使用(b1, b2) -> { throw new IllegalStateException(); }抛出异常而不添加addAll方法。)

作为旁注,可以简化用于查找最小数组大小的代码:您不需要插入Integer,您可以将每个数组映射到其长度并获取至少min()。这将返回OptionalInt;如果Stream为空,它可能会抛出异常而不是获取它的值,而是使用orElse(0),这样,在空的Stream的情况下,返回一个空列表。