Sreeni
Sreeni

Reputation: 75

How to group List of Lists using a certain criteria in Java 8

I have a data structure like below. I'm trying to group the objects in such a way like Map<String, List<String>> where key is the entryId and value is the List of groups it belongs to. entryId is always unique inside a group.

Example: entryId "1111" belongs to group1,group2,group3. I'm using the old java 7 way to iterate through the lists and checking. Is there any best possible way using Java8 Collectors/grouping to achieve this.

List<Group> where each Group object will have a list of Entry objects.

    [  
   {  
      "id":"group1",
      "entries":[  
         {  
            "entryId":"1111",
            "name":"test1"
         },
         {  
            "entryId":"2222",
            "name":"test2"
         },
         {  
            "entryId":"3333",
            "name":"test3"
         }
      ]
   },
   {  
      "id":"group2",
      "entries":[  
         {  
            "entryId":"4444",
            "name":"test1"
         },
         {  
            "entryId":"1111",
            "name":"test2"
         },
         {  
            "entryId":"2222",
            "name":"test3"
         }
      ]
   },
   {  
      "id":"group3",
      "entries":[  
         {  
            "entryId":"1111",
            "name":"test1"
         },
         {  
            "entryId":"5555",
            "name":"test2"
         },
         {  
            "entryId":"3333",
            "name":"test3"
         }
      ]
   }
]

So the expected out put is this :

    [  
   {  
      "1111":[  
         "group1",
         "group2",
         "group3"
      ]
   },
   {  
      "2222":[  
         "group1",
         "group2"
      ]
   },
   {  
      "3333":[  
         "group1",
         "group3"
      ]
   },
   {  
      "4444":[  
         "group2"
      ]
   },
   {  
      "5555":[  
         "group3"
      ]
   }
]

I'm using below way currently. which is working as expected, but is there a much simpler way in Java 8 I can achieve this.

    public Map<String, List<String>> mapEntries(List<Group> groups) {
    Map<String, List<String>> entryMaps = new HashMap<>();
    for (Group group : groups) {
        for (Entry entry : group.getEntries()) {
            List<String> groupsEntryBelongs = new ArrayList<>();
            if (groups.iterator().hasNext() && !entryMaps.keySet().contains(entry.getEntryId())) {
                updateGroups(groups, entry.getEntryId(), groupsEntryBelongs, entryMaps);
            }
        }
    }
    return entryMaps;
}

    void updateGroups(List<Group> groups, String id, List<String> groupsEntryBelongs, Map<String, List<String>> entryMaps) {
        for (Group group : groups) {
            for (Entry entry : group.getEntries()) {
                if (entry.getEntryId().equalsIgnoreCase(id)) {
                    groupsEntryBelongs.add(group.getId());
                }
            }
        }
        entryMaps.put(id, groupsEntryBelongs);
    }

Upvotes: 3

Views: 5435

Answers (4)

Abrar Hussain
Abrar Hussain

Reputation: 35

List<List<EmployeeHourLogDetails>> resultLisSalesman = new ArrayList<> 
(employeeHourLogHeader.getEmployeeHourLogDetails().stream()
                        .collect(Collectors.groupingBy(d -> 
d.getEmployeeId())).values());

This code demonstrates how to group a list into a list of lists based on a specific criterion using Java 8 Streams. Here, the employeeHourLogHeader.getEmployeeHourLogDetails() list is grouped by the employeeId field using Collectors.groupingBy. The resulting groups are extracted as a Collection<List> using .values() and wrapped into an ArrayList. Each sublist in resultLisSalesman contains all EmployeeHourLogDetails objects for a unique employeeId.

Upvotes: -1

Abrar Hussain
Abrar Hussain

Reputation: 35

List<List<EmployeeHourLogDetails>> resultLisSalesman = new ArrayList<> 
(employeeHourLogHeader.getEmployeeHourLogDetails().stream()
                        .collect(Collectors.groupingBy(d -> 
Arrays.asList(d.getEmployeeId(),
d.getName(),d.getAge()))).values());

Upvotes: 0

Dylan Bijnagte
Dylan Bijnagte

Reputation: 1356

Something like this ought to work, it requires making some sort of intermediate tuple object:

groups.stream()
    .flatMap(group -> group.getEntries().stream()
            .map(entry -> Map.entry(entry.getEntryId(), group.getId())))
    .collect(Colectors.groupingBy(Map.Entry::getKey,
            Colectors.mapping(Map.Entry::getValue, toList())));

Upvotes: 1

fps
fps

Reputation: 34450

You can do it as follows:

Map<String, Set<String>> entryMaps = new LinkedHashMap<>();
groups.forEach(group -> 
    group.getEntries().forEach(entry -> 
            entryMaps.computeIfAbsent(
                    entry.getEntryId().toLowerCase(),
                    k -> new LinkedHashSet<>())
                .add(group.getId())));

This iterates the groups, then each group's entries and uses Map.computeIfAbsent to put an entry with a new, empty LinkedHashSet if the key wasn't present, returning either this empty set or the one matching that key. Then, the group id is added to this returned set.

Note: I'm using a Set instead of a List for values, to avoid possible duplicates. And LinkedHashMap and LinkedhashSet guarantee insertion-order.

Upvotes: 4

Related Questions