如何在Java 8中使用特定的准则对列表列表进行分组

3
我有一个数据结构如下。我想以这样的方式对对象进行分组:Map<String,List<String>>,其中键是entryId,值是它所属的组列表。entryId在组内始终是唯一的。
例如:entryId“1111”属于group1,group2,group3。我正在使用旧的Java 7方法迭代列表并检查。是否有使用Java8 Collectors/grouping来实现此目标的最佳方法。 List<Group>,其中每个Group对象都有一个Entry对象列表。
    [  
   {  
      "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"
         }
      ]
   }
]

因此,期望的输出结果是这样的:
    [  
   {  
      "1111":[  
         "group1",
         "group2",
         "group3"
      ]
   },
   {  
      "2222":[  
         "group1",
         "group2"
      ]
   },
   {  
      "3333":[  
         "group1",
         "group3"
      ]
   },
   {  
      "4444":[  
         "group2"
      ]
   },
   {  
      "5555":[  
         "group3"
      ]
   }
]

我目前正在使用以下方式。虽然它能够按预期工作,但在Java 8中是否有更简单的方法可以实现这一点。

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

我使用了迭代组并获取第一个条目ID的方法,然后通过剩余的组来检查更新我创建的对象Map<String,List<String>>。我得到了我需要的结果,但是请建议如何在Java8中实现它。 - Sreeni
在问题中分享你尝试过的内容总是值得的,这可以让人更清楚你期望的输出。 - Naman
1
可能是Java 8 lambdas group list into map的重复问题。 - uli
@uli 不是我要找的。我更新了我的问题,并说明了我当前的预期输出方式。你指向的那个不同。我试图按内部列表中的值进行分组。 - Sreeni
3个回答

4
您可以按照以下步骤进行操作:
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())));

这个循环遍历了所有的分组,对于每个分组的条目,使用Map.computeIfAbsent方法将一个新的、空的LinkedHashSet添加到其中,如果键不存在,则返回这个空集合或与该键匹配的集合。然后,将该分组的id添加到返回的集合中。
注意:为了避免可能出现的重复,我使用了Set而非List。而LinkedHashMapLinkedhashSet保证了插入顺序。

1
谢谢。它起作用了。根据您的实现,我不得不声明为这样。 Map<String,LinkedHashSet<String>> entryMaps = new LinkedHashMap<>() - Sreeni

1

类似这样的东西应该可以工作,需要创建某种中间元组对象:

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

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

3
请问您能否为此添加一些解释说明? - cyberbrain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接