【问题标题】:What's a simple way to trim this group of data? (Java)修剪这组数据的简单方法是什么? (爪哇)
【发布时间】:2019-09-11 21:25:43
【问题描述】:

我正在练习用 Java 处理简单的 JSON 数据,但我有点卡住了。

假设我是一名面包师,并且我拥有多年来我的各种产品的一些数据。例如,我有三种产品:蛋糕、百吉饼和饼干。我的数据每年收集一次,因此 JSON 数据集示例可能类似于:

[ {"name": "cake", "consumers": 200, "tastiness": 8.0}, {"name": "cake", "consumers": 220, "tastiness": 8.3}, {"name": "bagel", "consumers": 1000, "tastiness": 6.4}, {"name": "bagel", "consumers": 1200, "tastiness": 7.5}, {"name": "bagel", "consumers": 800, "tastiness": 5.7}, {"name": "cookie", "consumers": 500, "tastiness": 9.6} ]

如您所见,有两个“cake”条目表示蛋糕存在两年,三个“bagel”条目表示百吉饼存在三年,等等。

我想浓缩这些数据以获得每种产品的加权平均美味。例如,蛋糕的平均味道是 (8.0*200 + 8.3*220)/(200+220) = 8.157,所以我希望我的新集合包含一个带有值的数据条目(“cake”,8.157),除了相应的百吉饼和饼干的平均味道。

解析 JSON 数据并提取我想要的值是微不足道的,但我正在努力的是提取/压缩具有相同名称的数据值并获得平均美味的最佳方法。

到目前为止,我考虑过为名称、consumerNumbers 和 tastiness 创建 arrayLists,但我意识到这可能有点混乱和不方便。

我目前正在考虑创建一个名为“Product”的单独类,其属性为“name”、“consumers”和“tastiness”,然后创建一个singlearrayList<Product>。但是,我坚持如何最好地遍历产品的数组列表并获取具有相同名称的产品并计算加权平均值。

我知道对于我的问题可能存在一个非常简单和简单的解决方案,但目前还没有出现,因此我们将不胜感激任何帮助。谢谢:)

【问题讨论】:

    标签: java json class arraylist


    【解决方案1】:

    我认为您创建具有上述属性的容器类的想法是个好主意。

    结合java.util.stream.Collectors 类中的groupingByreducing,您可以实现此目的。

    我们首先定义一个类来保存我们的数据:

    public class SugarStats {
        private String name;
        private long consumers;
        private double tastiness;
    
        // Constructor(name, consumers, tastiness) and getters left out for brevity
    }
    

    我们将使用这个容器类来计算平均值,所以我们要添加一个方法:

    public double getAverageTastiness() {
        return this.tastiness / this.consumers;
    }
    

    此外,我假设从 JSON 到 POJO 的转换已经完成,并且您的数据如下所示:

    List<SugarStats> stats = Arrays.asList(
        new SugarStats("cake", 200, 8.0),
        new SugarStats("cake", 220, 8.3),
        new SugarStats("bagel", 1000, 6.4),
        new SugarStats("bagel", 1200, 7.5),
        new SugarStats("bagel", 800, 5.7),
        new SugarStats("cookie", 500, 9.6));
    

    然后我们将执行以下操作:

    1. 我们将通过列表进行流式传输:

      stats.stream()
      
    2. 然后我们将总结每个SugarStats的总美味分数,而不是单个条目的分数:

      .map(t -> new SugarStats(t.getName(), t.getConsumers(), t.getConsumers() * t.getTastiness()))
      

      例如,cookiesugarstats 实例现在的味道为 500 * 9.6 = 4800

    3. 然后我们收集结果,按名称分组。这通常会返回一个以name 为键的Map 和一个带有所有值的List&lt;SugarStats&gt;。但是,我们对List 不感兴趣,我们只对平均值感兴趣。所以我们提供了一个 reducing 下游收集器,它收集所有 SugarStats 并将它们组合起来,总计消费者数量和美味。

      例如,new SugarStats("cake", 200, 1600.0) + new SugarStats("cake", 220, 1826.0) 将变为 new SugarStats("cake", 420, 3426)

      .collect(groupingBy(t -> t.getName(),
          reducing(
              new SugarStats("", 0, 0),
              (p1, p2) -> new SugarStats(
                  p2.getName(),
                  p1.getConsumers() + p2.getConsumers(),
                  p1.getTastiness() + p2.getTastiness()
              )
          )
      ));
      

    现在我们可以品尝到美味了:

    result.values().stream()
        .forEach(t -> System.out.println(t.getName() + ": " + t.getAverageTastiness()));
    

    Ideone example here.

    【讨论】:

      【解决方案2】:

      因此,您有多种产品和任意数量的组,您想从事这些工作。

      您是否考虑过使用Map?你可以使用类似Map&lt;String, List&lt;Product&gt;&gt;

      您可以使用 Java 8 流(流式传输 List&lt;Product&gt;)并根据产品名称进行分组来构建地图。

      最后,你可以for-each遍历地图的keySetList中的产品列表

      例子:

         List<Product> products = buildProductsList();
         Map<String, List<Product>> productsGroupedByName = products.stream()
            .collect(Collectors.groupingBy(Product::getName));
         for(String name : productsGroupedByName.keySet()) {
            System.out.println("The name is: " + name);
            for (Product product : productsGroupedByName.get(name)) {
                // do something with the products
            }
         }
      

      【讨论】:

      • 你的“groupingBy”从何而来?
      • 它来自 Collectors 包。 import static java.util.stream.Collectors.groupingBy;
      • 嗯,好的,谢谢。对于每个循环的第一个,从 productsGroupedByName 获取名称,我得到一个“只能迭代数组或 java.lang.Iterable 的实例”红色下划线,这很奇怪,因为 Maps 不是可迭代的?
      • 我的错,我忘了给它添加 keySet。它应该是for(String name : productsGroupedByName.keySet()) - 我也更新了我的答案。
      • 关于如何以有效的方式获得美味加权平均值的任何提示?既然我已经对每个产品进行了分析,我是否会遍历每个产品并将消费者和美味值存储到一个单独的列表中,直到名称更改,然后为我创建的每个列表分别执行加权平均计算?还是有更好的办法?
      猜你喜欢
      • 1970-01-01
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-06
      • 2015-01-05
      相关资源
      最近更新 更多