我正在尝试弄清楚如何使用 Streams API 来实现一个 zip 函数,该函数将无限数量的 int[] 作为参数;从每个元素中取出第 i 个元素;将它们放在元组中(显然需要自定义元组对象——我有)并返回元组列表(即列表)。
本质上,对于:
{ 1, 2, 3 }
{ 4, 5, 6 }
提议的方法应该返回:
[ 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;
}
最佳答案
一个解决方案是在索引上创建一个 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
;我使用 orElse(0)
代替获取它的值(如果 Stream 为空则可能会引发异常),这样,在 Stream 为空的情况下,将返回一个空列表。
关于java - 如何使用 Java 8 Streams 以特定方式实现 zip?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34838563/