首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用减(3个参数)函数传递集合- streams java 8

使用减(3个参数)函数传递集合- streams java 8
EN

Stack Overflow用户
提问于 2014-09-17 00:12:30
回答 2查看 3.5K关注 0票数 6

我试图使用前面的两个值,使用java 8的流来计算一个值的乘法。我想要调用一个函数,它将返回一个数组/列表/集合。我正在创建一个列表,并在其中添加1,2。

假设列表名是结果。

代码语言:javascript
代码运行次数:0
运行
复制
public static void main (String[] args) { 
List<Integer> result = new ArrayList<Integer>();
result.add(1);
result.add(2);
int n = 5; //n can be anything, choosing 5 for this example
res(n, result);
//print result which should be [1, 2, 2, 4, 8]
}
public static List<Integer> res(int n, List<Integer> result ) {
           result.stream()
                 .limit(n)
                 .reduce(identity, (base,index) -> base);

       //return result;
}

现在,问题是试图将结果传递到流中,以便使用流更新列表中的新值。根据java教程,这是可能的,尽管效率很低。

“如果减少操作涉及向集合添加元素,那么每次累加器函数处理元素时,它都会创建一个包含元素的新集合,这是效率低下的。”

我是否需要使用可选的第三个参数BinaryOperator组合器来组合列表+结果?

代码语言:javascript
代码运行次数:0
运行
复制
<U> U reduce(U identity,
         BiFunction<U,? super T,U> accumulator,
         BinaryOperator<U> combiner)

简而言之,我想传递一个包含两个值的列表,并让函数查找前两个值的乘法(1,2),将其添加到列表中,并找到最后两个值(2,2)的乘法,并将其添加到列表中,直到流达到极限为止。

EN

回答 2

Stack Overflow用户

发布于 2014-09-17 01:40:08

看起来你在尝试实现一个重复的关系。reduce方法将一些函数应用于流中的一组预先存在的值。您不能使用reduce并将还原器函数的中间结果“反馈”到流中,这是实现递归关系所需的。

使用流实现递归关系的方法是使用流工厂方法之一Stream.generateStream.iterateiterate工厂似乎提出了最明显的方法。在您的示例中,需要为每个递归函数的应用程序保留的状态需要两个int,因此不幸的是,我们必须创建一个对象来保存这些对象:

代码语言:javascript
代码运行次数:0
运行
复制
static class IntPair {
    final int a, b;
    IntPair(int a_, int b_) {
        a = a_; b = b_;
    }
}

使用此状态对象,您可以创建一个实现所需重复使用的流:

代码语言:javascript
代码运行次数:0
运行
复制
Stream.iterate(new IntPair(1, 2), p -> new IntPair(p.b, p.a * p.b))

一旦有了这样的流,将值收集到列表中是一件很简单的事情:

代码语言:javascript
代码运行次数:0
运行
复制
List<Integer> output =
    Stream.iterate(new IntPair(1, 2), p -> new IntPair(p.b, p.a * p.b))
          .limit(5)
          .map(pair -> pair.a)
          .collect(Collectors.toList());
System.out.println(output);

[1, 2, 2, 4, 8]

另外,您可以使用相同的技术来生成Fibonacci序列。您所做的就是提供一个不同的起始值和迭代函数:

代码语言:javascript
代码运行次数:0
运行
复制
Stream.iterate(new IntPair(0, 1), p -> new IntPair(p.b, p.a + p.b))

您还可以使用Stream.generate实现类似的递归关系。这还需要一个助手类。helper类实现结果值的Supplier,但它也需要维护状态。因此,它需要是可变的,这在我的书中是有点恶心的。迭代函数还需要放入生成器对象中。这使得它不像IntPair对象那么灵活,后者可以用于创建任意递归。

票数 11
EN

Stack Overflow用户

发布于 2014-09-17 12:45:51

为了完整起见,这里有一个不需要额外类的解决方案。

代码语言:javascript
代码运行次数:0
运行
复制
List<Integer> output = Stream.iterate(
    (ToIntFunction<IntBinaryOperator>)f -> f.applyAsInt(1, 2),
    prev -> f -> prev.applyAsInt((a, b) -> f.applyAsInt(b, a*b) )
)
.limit(9).map(pair -> pair.applyAsInt((a, b)->a))
.collect(Collectors.toList());

这是一种不需要中间值存储的功能方法。但是,由于Java不是一种函数式编程语言,也没有对这样的递归函数定义进行优化,因此不建议对较大的流进行优化。

因为在这个例子中,一个更大的流无论如何都会在数值上溢出,而且计算成本很低,所以这种方法是可行的。但是对于其他用例,在用普通的Java (如Stuart Marks’ answer)解决这样的问题时,您肯定会更喜欢存储对象。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25880331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档