首页 > 解决方案 > 按值分组地图列表并通过排序合并为分组列表

问题描述

我想按值对地图列表进行分组,并在某些条件下将插入(合并)作为分组列表。按值“yr”分组并按相同“类别”合并“标签”,然后将“价格”汇总在一起,然后按“价格”降序排列

List<Grocery> groceryList = new ArrayList<>();

Grocery grocery = new Grocery();

List<HahsMap<String, Object>> tagList = new ArrayList<>();

HashMap<String, Object> tagMap = new HashMap<>();

## feeding data example
tagMap.put("category", "A");
tagMap.put("name", "Apple");
tagMap.put("price", 10);

tagList.add(tagMap);


grocery.setYr(String yr);
grocery.setTag(List<Hashmap<String, Object>> tagList);

groceryList.add(grocery);

这是地图列表的示例。

List<Grocery> groceryList = 

[
  {
    "yr": "2021",
    "tag": [
      {
        "Category": "A",
        "Name": "Apple",
        "Price": 10
      }
    ]
  },
  {
    "yr": "2021",
    "tag": [
      {
        "Category": "A",
        "Name": "Apple",
        "Price": 10
      }
    ]
  },
  {
    "yr": "2021",
    "tag": [
      {
        "Category": "B",
        "Name": "Banana",
        "Price": 5
      }
    ]
  },
  {
    "yr": "2020",
    "tag": [
      {
        "Category": "A",
        "Name": "Apple",
        "Price": 10
      }
    ]
  },
  {
    "yr": "2020",
    "tag": [
      {
        "Category": "B",
        "Name": "Banana",
        "Price": 30
      }
    ]
  },
  {
    "yr": "2020",
    "tag": [
      {
        "Category": "C",
        "Name": "Candy",
        "Price": 10
      }
    ]
  },
  {
    "yr": "2020",
    "tag": [
      {
        "Category": "C",
        "Name": "Candy",
        "Price": 30
      }
    ]
  },
  {
    "yr": "2020",
    "tag": [
      {
        "Category": "A",
        "Name": "Apple",
        "Price": 10
      }
    ]
  }
]

这是我想要得到的示例输出

List<Grocery> result =

[
  {
    "yr": "2021",
    "tag": [
      {
        "Category": "A",
        "Name": "Apple",
        "Price": 20
      },
      {
        "Category": "B",
        "Name": "Banada",
        "Price": 5
      }
    ]
  },
  {
    "yr": "2020",
    "tag": [
      {
        "Category": "C",
        "Name": "Candy",
        "Price": 40
      },
      {
        "Category": "B",
        "Name": "Banada",
        "Price": 30
      },
      {
        "Category": "A",
        "Name": "Apple",
        "Price": 20
      }
    ]
  }
]

我知道将所有条件合二为一很棘手,有人可以帮我吗?如果至少我能对此有一些想法,那将不胜感激。

我尝试先将它们分组为“年”,然后尝试找到要映射的值,然后用相同的“类别”对它们进行排序,然后总结..但我不知道对它们进行排序并将它们与 summed 合并在一起涨价。。

提前致谢!!

标签: java

解决方案


请检查这是否是您要查找的内容。

String inputJson = "[{\"yr\":\"2021\",\"tag\":[{\"Category\":\"A\",\"Name\":\"Apple\",\"Price\":10}]},{\"yr\":\"2021\",\"tag\":[{\"Category\":\"A\",\"Name\":\"Apple\",\"Price\":10}]},{\"yr\":\"2021\",\"tag\":[{\"Category\":\"B\",\"Name\":\"Banana\",\"Price\":5}]},{\"yr\":\"2020\",\"tag\":[{\"Category\":\"A\",\"Name\":\"Apple\",\"Price\":10}]},{\"yr\":\"2020\",\"tag\":[{\"Category\":\"B\",\"Name\":\"Banana\",\"Price\":30}]},{\"yr\":\"2020\",\"tag\":[{\"Category\":\"C\",\"Name\":\"Candy\",\"Price\":10}]},{\"yr\":\"2020\",\"tag\":[{\"Category\":\"C\",\"Name\":\"Candy\",\"Price\":30}]},{\"yr\":\"2020\",\"tag\":[{\"Category\":\"A\",\"Name\":\"Apple\",\"Price\":10}]}]";
    ObjectMapper objectMapper = new ObjectMapper();

    //convert json to input Grocery List using jackson object mapper
    List<Grocery> groceries = objectMapper.readValue(inputJson, new TypeReference<List<Grocery>>() {
    });

    List<Grocery> output = new ArrayList<>();
    //group all groceries by year
    Map<String, List<Grocery>> groceriesByYear = groceries.stream().collect(Collectors.groupingBy(grocery -> grocery.getYr()));

    groceriesByYear.keySet().forEach(year -> {
        //for each year, get the grocery list
        List<Grocery> groceryList = groceriesByYear.get(year);
        //merge tags which have same category
        Map<String, Tag> tagsPerCategory = groceryList.stream().flatMap(grocery -> grocery.getTag().stream()).collect(Collectors.toMap(Tag::getCategory, Function.identity(),
                (tag1, tag2) -> {
                    //merge function, sum up the price of tag which has same category
                    tag1.setPrice(tag1.getPrice() + tag2.getPrice());
                    return tag1;
                }));
        //create new grocery object with required data
        Grocery grocery = new Grocery();
        grocery.setYr(year);
        grocery.setTag(new ArrayList<>(tagsPerCategory.values()));
        output.add(grocery);
    });
    //output list will have groceries grouped by year and tag with summed up price

编辑

您可以对标签流进行过滤以避免空标签对象,如果您认为价格可以为空,则可以添加非空检查,或者如果尚未设置价格,则可以定义一种方法来提供默认值,如下所示

public static <T> T getValueOrDefault(T value, T defaultValue) {
    return value != null ? value : defaultValue;
}

你的 tagsPerCategory 看起来像下面

Map<String, Tag> tagsPerCategory = groceryList.stream().flatMap(grocery -> grocery.getTag().stream()).filter(tag -> tag != null && tag.getPrice() != null)
                .collect(Collectors.toMap(Tag::getCategory, Function.identity(),
                        (tag1, tag2) -> {
                            //sum up the price of tag which has same category
                            tag1.setPrice(getValueOrDefault(tag1.getPrice(), 0) + getValueOrDefault(tag2.getPrice(), 0));
                            return tag1;
                        }));

推荐阅读