当前位置: 首页 > 知识库问答 >
问题:

Java Collectors.Stream:POJO构建和设置多个聚合值[重复]

符鸿光
2023-03-14
public class Item{
   String name;
   Double quantity;
   Double price;
   Double totalDollarAmount;

    public Item(String name, Double quantity, Double price) {
        this.name = name;
        this.quantity= quantity;
        this.price = price;
    }

   //Basic Getters and setters

   public Double getTotalDollarAmount(){
      return getQuantity()*getPrice();
   }
}

列表 中,我希望能够快速计算我购买的每件商品的数量、平均价格以及为该商品花费的总金额。假设对于这个场景,我有以下列表:

        List<Item> itemsOnly = Arrays.asList(
                new Item("apple", 10.0, 9.99),
                new Item("banana", 20.0, 19.99),
                new Item("orange", 10.0, 29.99),
                new Item("watermelon", 10.0, 29.99),
                new Item("papaya", 20.0, 9.99),
                new Item("apple", 100.0, 9.99),
                new Item("apple", 20.0, 9.99)
        );

如果我想获得列表中每个唯一项目的总数量、平均价格和总美元金额,我可以这样做:

System.out.println("Total Quantity for each Item: " + itemsOnly.stream().collect(
                Collectors.groupingBy(Item::getName, Collectors.summingDouble(Item::getQuantity))));
System.out.println("Average Price for each Item: " + itemsOnly.stream().collect(
                Collectors.groupingBy(Item::getName, Collectors.averagingDouble(Item::getPrice))));
System.out.println("Total Dollar Amount for each Item: " + itemsOnly.stream().collect(
                Collectors.groupingBy(Item::getName, Collectors.summingDouble(Item::getTotalDollarAmount))));

这将返回以下内容:

Total Quantity for each Item: {papaya=20.0, orange=10.0, banana=20.0, apple=130.0, watermelon=10.0}
Average Price for each Item: {papaya=9.99, orange=29.99, banana=19.99, apple=9.99, watermelon=29.99}
Total Dollar Amount for each Item: {papaya=199.8, orange=299.9, banana=399.79999999999995, apple=1298.7, watermelon=299.9}

共有1个答案

澹台胜
2023-03-14

你快到了。若要将分组项合并到单个项中,可以使用Reduction收集器。

下面是一个方法:

首先,定义一种合并两项的方式:

public static Item merge (Item i1, Item i2) {
    final double count = i1.quantity + i2.quantity;
    final double avgPrice = (i1.quantity * i1.price + i2.quantity * i2.price) / count;
    return new Item(i1.name, count, avgPrice);
}
import java.util.Map;
import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.Optional;

public class Main
{
    public static void main(String[] args) {        
        List<Item> itemsOnly = Arrays.asList(
                new Item("apple", 10.0, 9.99),
                new Item("banana", 20.0, 19.99),
                new Item("orange", 10.0, 29.99),
                new Item("watermelon", 10.0, 29.99),
                new Item("papaya", 20.0, 9.99),
                new Item("apple", 100.0, 9.99),
                new Item("apple", 20.0, 9.99)
        );
        
        Map<String, Item> groupedItems = itemsOnly.stream().collect(
                Collectors.groupingBy(
                     item -> item.name,
                     Collectors.collectingAndThen(
                         Collectors.<Item>reducing(Main::merge),
                         Optional::get // No need for null check: grouping should send at least one element to the reducer
                    )
                )
        );

        for (Item i : groupedItems.values()) System.out.println(i);                 
    }
    
    public static Item merge (Item i1, Item i2) {
        final double count = i1.quantity + i2.quantity;
        final double avgPrice = (i1.quantity * i1.price + i2.quantity * i2.price) / count;
        return new Item(i1.name, count, avgPrice);
    }
    
    public static class Item {
        public final String name;
        public final double quantity;
        public final double price;

        public Item(String name, double quantity, double price) {
            this.name = name;
            this.quantity= quantity;
            this.price = price;
        }

        public double getTotalDollarAmount(){
          return quantity*price;
        }
        
        public String toString() { return String.format("%s: quantity: %d, price: %f, total: %f", name, (int) quantity, price, getTotalDollarAmount()); }
    }
}
 
Map<String, Item> groupedItems = itemsOnly.stream().collect(
            Collectors.toMap(
                item -> item.name,
                Function.identity(),
                Main::merge
            )
);
 类似资料:
  • 假设我们有一个DF,其受尊重的用户ID中有重复项,但名称不同,当然也可以是重复项。 目的是分别聚合和计算用户ID及其名称的均值和均方差。一个所需的输出示例: 因此我的问题是: 有哪些选项可以根据UserID聚合Names,而不会丢失信息(Hank被强制插入Ed等,就像sumise()或mutate()一样) 按照我的想法,R必须检查哪个名称对应于用户ID,以及是否匹配;汇总并计算平均值 与此同时,

  • 假设我有以下JSON结构,我希望按性别分组,并希望在同一字段中返回多个文档值: 现在我知道我可以做这样的事情,但是我需要把年龄和名字合并到一个字段中。

  • 我有一个mongo查询,用于展开四个对象数组,并根据匹配条件过滤数据。如何在Spring data mongodb中执行相同的操作 我使用过单次放卷,但找不到任何具有多次放卷和匹配操作的。

  • 我在这里读了很多问题和答案,但我找不到一个能消除我疑虑的aswer。 我有一个用管理的大型Java项目(我们称之为MainProj),它有许多依赖项,其中一些是我和我的团队完成的其他独立项目。 我所做的是为每个相关项目创建一个maven项目,将每个项目安装到我的存储库中,并使用标准的导入导入到MainProj中。 我已经读过superPom(或parent pom)的概念,但我不知道它是如何工作的

  • 我有索引,其中每个文档都有这样的结构: 我需要计算每个演员对应的电影数量(演员可以在actor_1_name、actor_2_name或actor_3_name字段中) 这3个字段的映射是: 有没有一种方法,我可以聚合的结果,可以结合所有3个演员领域的条款,并给出一个单一的聚合。 目前,我正在为每个actor字段创建单独的聚合,并通过我的JAVA代码将这些不同的聚合合并成一个。 通过创建不同的聚合

  • 我正在尝试设置一个搜索查询,该查询应通过多级嵌套字段复合聚合集合,并从该集合中提供一些子聚合指标。我能够按预期使用其存储桶获取复合聚合,但所有存储桶的子聚合指标都带有。我不确定我是否未能正确指出子聚合应考虑哪些字段,或者它是否应放置在查询的不同部分中。 我的收藏看起来类似于以下内容: 贝娄,你可以找到我已经尝试了。尽管所有文档都有一个设置的点击值,但所有存储桶都带有点击总数。 到目前为止,我的回应