【问题标题】:Java 8 Stream - aggregate and return aggregation stepsJava 8 Stream - 聚合和返回聚合步骤
【发布时间】:2017-03-06 12:29:57
【问题描述】:

我是 java 8 流 api 的新手,我正在寻找一种解决方案来运行我的对象列表并聚合某些属性,以便最终能够获得该属性类型的新列表和所有聚合结果。

例如,我的列表里面有 10 个人对象,我想要一个基于第一人年龄的所有年龄差异的列表

即使在 java 中也可以使用流?

例如:

person1.age = 10
person2.age = 12
person3.age = 20
person4.age = 25
person5.age = 30

在执行流魔术之后,结果应该是 int 类型并且看起来像这样

0
2 //based on first age 12 - 10
10 // based on first age 20 - 10
15 // ...
20

【问题讨论】:

  • 即使在java中也可以不用写太多代码吗?我什至没有找到你到目前为止尝试过的代码。
  • 我的意思是,如果不为流和那些东西编写自定义收集器,这是可能的..
  • 让我们看看,你尝试了什么,然后让我们找出可以做些什么来改进。

标签: java java-8 java-stream


【解决方案1】:

我假设你有一个名为Person 的类,上面有一个getAge() getter。然后你可以这样做:

list.stream()
    .skip(1)
    .map(Person::getAge)
    .map(age -> age - list.get(0).getAge())
    .map(Math::abs)
    .forEach(System.out::println);

.skip(1) - 跳过列表中的第一个人,因此结果不会包含通过将第一个人的年龄与他们自己进行比较而产生的 0。

.map(Math::abs) - 取绝对值,因为“差”总是正的(我有10年你有20年,或者我有20年你有10年,差是10)。

您可能需要添加 .distinct() 以删除重复项。

最后,您可能想要使用不同的终端操作 - 例如.collect(toList()),而不是打印。

【讨论】:

    【解决方案2】:

    假设列表已经排序(如果没有,则需要按年龄排序)。您可以提取lst.get(0).getAge(),然后执行以下操作:

    List<Integer> diff = lst.stream().map((x)->x.getAge()-firstAge).collect(Collectors.toList());
    

    我不容忍命名任何 List lst。这是不好的做法,但鉴于您没有与我们分享任何代码,我不知道您将人员列表命名为什么。

    【讨论】:

    • 我的意思是,无需为流和那些东西编写自定义收集器就可以了来自 OP 的评论
    • @nullpointer 实际上我认为这不会被视为“自定义收集器”,因为它利用Collectors.toList()Stream 生成返回的List
    • {return ...;} lambda 语法似乎有点不必要
    • 有没有办法获取上一个和实际的项目并将它们累积到使用流输出的新列表中?
    • @Jo-ing 这是一个完全不同的问题。它已经得到了回答。 stackoverflow.com/questions/20470010/…
    【解决方案3】:

    我假设你有一个 Person 类,我在这个假设上编写了我的代码,因为你给了任何东西。

    public static void main(String [] args) {
        List<Person> list = new ArrayList<Person>();
        Person person1 = new Person();
        person1.age = 10;
        Person person2 = new Person();
        person2.age = 12;
        Person person3 = new Person();
        person3.age = 20;
        Person person4 = new Person();
        person4.age = 25;
        Person person5 = new Person();
        person5.age = 30;
    
        list.add(0,person1);
        list.add(person2);
        list.add(person3);
        list.add(person4);
        list.add(person5);
    
        list.stream().forEach(person -> System.out.println(person.age-list.get(0).age));
    }
    

    这里有

    如果你想把值放在一个列表中:

    List<Integer> list2 = new ArrayList<Integer>();
    list.stream().forEach(person -> list2.add(person.age-list.get(0).age));
    

    因为你写了person.age=10,看来你将age的可见性设置为public,这不是很好,你需要将它设置为private并为其提供一个getter:

    public int getAge(){
        return this.age;
    }
    

    【讨论】:

    • list.add(0,person1); - 这个0 是多余的。您的流应该有.skip(1),否则它将始终打印 0 作为第一个结果,因为它将第一人称与自身进行比较。最后,在单个 Lamba 中进行如此多的操作是一种不好的做法 - 您应该使用多个 .map(...) 来代替。
    • 关于你的编辑,你不应该有一个有状态的消费者函数来添加到一些列表中。这就是.collect(...) 的用途。
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 2021-09-10
    • 2014-10-26
    相关资源
    最近更新 更多