Java Lambda单个流上的多个操作

时间:2016-08-15 05:25:49

标签: java lambda

场景:我有一个包含2个函数的对象 - >

<Integer> getA(); <Integer> getB();

我有一个对象列表,比如List<MyObject> myObject

目标迭代List并获取对象列表中A和B的总和。

我的解决方案

myObject.stream().map(a -> a.getA()).collect(Collectors.summingDouble());

myObject.stream().map(a -> a.getB()).collect(Collectors.summingDouble());

问题:如何同时执行这两项操作?这样我就不必在原始列表上迭代两次。

@Edit:我这样做是因为我使用的一些过滤器是O(n ^ 3)。两次这样做真的很糟糕。

基准:如果程序在i5上运行半小时,那么它是T还是2T真的很重要。这是在更少的数据上,如果我在群集上运行,我的数据也会更大。

如果你能在一行中做到这一点很重要!

2 个答案:

答案 0 :(得分:3)

您需要编写另一个类来存储总值,如下所示:

public class Total {
    private int totalA = 0;
    private int totalB = 0;

    public void addA(int a) {
        totalA += a;
    }

    public void addB(int b) {
        totalB += b;
    }

    public int getTotalA() {
        return totalA;
    }

    public int getTotalB() {
        return totalB;
    }
}

然后使用

收集值
Total total = objects.stream()
        .map(o -> (A) o)
        .collect(Total::new,
                (t, a) -> {
                    t.addA(a.getA());
                    t.addB(a.getB());
                },
                (t1, t2) -> { });
//check total.getTotalA() and total.getTotalB()

您也可以使用AbstractMap.SimpleEntry<Integer, Integer>替换Total以避免编写新类,但它仍然有点奇怪,因为A / B不属于键值关系。

答案 1 :(得分:0)

最优化的可能仍然是for循环。虽然流选择具有并行性作为选项,但很可能很快变得有效。 将两个循环合二为一不一定更快。

一项改进是使用int代替Integer

List<String> list = Arrays.asList("tom","terry","john","kevin","steve");
int n = list.stream().collect(Collectors.summingInt(String::length));
int h = list.stream().collect(Collectors.summingInt(String::hashCode));

我赞成这个解决方案。

如果有人做一个循环,有两种选择:

  • 在他们自己的班级中投入两个。您可能滥用java.awt.Point类与int x和int y。
  • 把两个整体放进去。当没有溢出时,人们甚至可以在长的循环中求和。

后者:

List<String> list = Arrays.asList("tom","terry","john","kevin","steve");
long nh = list.stream()
    .collect(Collectors.summingLong((s) -> (s.hashCode() << 32) | s.length()));
    int n = (int) nh;
    int h = (int) (nh >> 32L);