简体   繁体   中英

group a list of map by value and merge as grouped lists by sorting

I would like to group a list of maps by value and insert(merge) as grouped lists in certain conditions. Group by a value "yr" and merge "tag" by the same "category" then sum up the "price" them together, then after order in descending order by "price"

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

This is an example of a list of maps.

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
      }
    ]
  }
]

This is the sample output I want to get

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
      }
    ]
  }
]

I know this is tricky to combine all the condition into one, could anyone help me out?? It will be really appreciated if at least I could have some ideas what to do about this..

I tried to group them in a 'yr' first, and try to find the values to map out then sort them out with the same 'category' then sum up.. but i have no clue on sorting them and merge them together with summed up 'price'..

Thanks in advance!!

Please check If this is what you are looking for.

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

Edit

You can do filter on tag stream to avoid null tag objects and add not null check if you think price can be null or you can define a method to provide default value if price is not already set like below

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

and your tagsPerCategory looks like below

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;
                        }));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM