Java中的Groupby计数

时间:2019-10-10 00:17:39

标签: java collections java-8

从c#迁移到Java方面,我还很陌生。我有以下课程。

class Resource {
    String name;
    String category;
    String component;
    String group;
}

我想知道以下数字: 1.类别中的资源计数。 2.每个类别中组件的不同数量。 (组件名称可以重复) 3.按类别和组分组的资源计数。

使用Collectors.groupingBy可以取得一些成功。但是结果总是这样。

Map<String, List<Resource>>

要获得计数,我必须解析键集并计算大小。 使用c#linq,我可以轻松计算上述所有指标。 我假设在Java中肯定还有更好的方法可以做到这一点。请告知。

2 个答案:

答案 0 :(得分:1)

对于#1,我将Collectors.groupingByCollectors.counting一起使用:

Map<String, Long> resourcesByCategoryCount = resources.stream()
        .collect(Collectors.groupingBy(
                 Resource::getCategory,
                 Collectors.counting()));

这将Resource元素按category分组,计数其中有多少属于每个类别。

对于#2,我不会使用流。相反,我将使用Map.computeIfAbsent操作(在Java 8中引入):

Map<String, Set<String>> distinctComponentsByCategory = new LinkedHashMap<>();
resources.forEach(r -> distinctComponentsByCategory.computeIfAbsent(
                       r.getCategory(),
                       k -> new HashSet<>())
         .add(r.getGroup()));

这首先创建一个LinkedHashMap(保留插入顺序)。然后,对Resource元素进行迭代并将其放入此映射中,以使其按category分组,并将每个group添加到映射到每个HashSet的位置类别。由于集合不允许重复,因此任何类别都不会有重复的组。然后,不同的组数就是每个组的大小。

对于#3,我将再次使用Collectors.groupingByCollectors.counting,但是我将使用复合键进行分组:

Map<List<String>, Long> resourcesByCategoryAndGroup = resources.stream()
        .collect(Collectors.groupingBy(
                 r -> Arrays.asList(r.getCategory(), r.getGroup()), // or List.of
                 Collectors.counting()));

这将Resource元素按categorygroup分组,计数每个(category, group)对中有多少个元素。对于分组键,使用的是两个元素的List<String>,其中category是其第一元素,component是其第二元素。

或者,您可以使用嵌套分组来代替使用组合键:

Map<String, Map<String, Long>> resourcesByCategoryAndGroup = resources.stream()
        .collect(Collectors.groupingBy(
                 Resource::getCategory,
                 Collectors.groupingBy(
                            Resource::getGroup,
                            Collectors.counting())));

答案 1 :(得分:0)

感谢Fedrico的详细回复。 #1和#3表现出色。对于#2,我希望看到Map的输出。这是我目前正在使用的代码以获取该计数。这是不使用旧样式的收集器的。

    HashMap<String, HashSet<String>> map = new HashMap<>();
for (Resource resource : resources) {
            if (map.containsKey(resource.getCategory())) {
                map.get(resource.getCategory()).add(resource.getGroup());
            } else 
                HashSet<String> componentSet = new HashSet<>();
                componentSet.add(resource.getGroup());
                map.put(resource.getCategory(), componentSet);
            }
        }

        log.info("Group count in each category");
        for (Map.Entry<String, HashSet<String>> entry : map.entrySet()) {
            log.info("{} - {}", entry.getKey(), entry.getValue().size());
        }