如何在Java 8中使用特定条件对列表列表进行分组

时间:2018-11-12 01:55:08

标签: java java-8 java-stream grouping

我的数据结构如下。我正在尝试以Map<String, List<String>>之类的方式对对象进行分组,其中key是entryId,value是它所属的组的列表。 entryId在组内始终是唯一的。

示例:entryId“ 1111”属于group1,group2,group3。我正在使用旧的Java 7方法来遍历列表和检查。是否有使用Java8收集器/分组的最佳方法来实现这一目标。

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

3 个答案:

答案 0 :(得分: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 :(得分:1)

您可以这样做

Map<String, List<String>> groupIdsByEntryId = groups.stream()
    .flatMap(g -> g.getEntries().stream()
        .map(e -> new AbstractMap.SimpleEntry<>(e.getEntryId(), g.getId())))
    .collect(Collectors.groupingBy(Map.Entry::getKey, TreeMap::new,
        Collectors.mapping(Map.Entry::getValue, Collectors.toList())));

为entryId和groupId值的每种组合创建一个简单的map条目。然后使用groupingBy收集器针对每个entryId获取List的groupId值。如果需要按键排序,则将TreeMap::new传递给操作符的mapFactory重载。

这是输出,

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

答案 2 :(得分:0)

类似的事情应该起作用,它需要制作某种中间元组对象:

list.stream()
.flatMap(group ->
   group.getEntries.stream()
        .map(entry -> new GroupEntry(group.getId(), entry.getEntryId()))
)
.collect(
   Collectors.groupingBy(GroupEntry::getEntryId, Collectors.mapping(GroupEntry::getGroupId, Collectors.toList())));