修剪此组数据的简单方法是什么? (Java)

时间:2019-09-11 21:25:43

标签: java json class arraylist

我正在练习用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} ]

如您所见,有两个“蛋糕”条目表示蛋糕已经存在两年,有三个“百吉饼”条目表明面包圈已经存在三年,等等。

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

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

到目前为止,我已经考虑过为名称,消费者编号和美味程度创建arrayLists,但是我意识到这可能有点混乱和不便。

我目前正在考虑制作一个单独的名为“产品”的类,其属性为“名称”,“消费者”和“美味”,然后创建一个单个 arrayList<Product>。但是,我坚持如何最好地遍历产品的arrayList并获取具有相同名称的产品并计算加权平均值。

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

2 个答案:

答案 0 :(得分:2)

因此,您要使用多种产品和任意数量的组。

您是否考虑过使用Map?您可以使用类似Map<String, List<Product>>

您可以使用Java 8流(流List<Product>)并按产品名称分组来构建地图。

最后,您可以遍历地图的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
      }
   }

答案 1 :(得分:2)

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

结合使用groupingBy类中的reducingjava.util.stream.Collectors,可以实现这一目标。

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

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()))
    

    例如, cookie sugarstats实例现在的口味为 500 * 9.6 = 4800

  3. 然后,我们按名称分组收集结果。通常,这将返回一个以Map为键的name和一个带有所有值的List<SugarStats>。但是,我们对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