Groupby считает в Java - PullRequest
       48

Groupby считает в Java

2 голосов
/ 10 октября 2019

Я довольно новичок в Java, переходя с C #. У меня есть следующий класс.

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

Я хочу знать следующие цифры: 1. Количество ресурсов в категории. 2. Различное количество компонентов в каждой категории. (имена компонентов могут дублироваться) 3. Количество ресурсов, сгруппированных по категориям и группам.

Мне удалось добиться небольшого успеха, используя Collectors.groupingBy. Тем не менее, результат всегда такой:

Map<String, List<Resource>>

Чтобы получить количество, мне нужно проанализировать набор ключей и вычислить размеры. Используя c # linq, я могу легко вычислить все вышеперечисленные показатели. Я предполагаю, что определенно есть лучший способ сделать это и в Java. Пожалуйста, сообщите.

Ответы [ 2 ]

1 голос
/ 10 октября 2019

Для # 1 я бы использовал Collectors.groupingBy вместе с Collectors.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 (который сохраняет порядок вставки * 1024). *). Затем элементы Resource повторяются и помещаются в эту карту таким образом, что они группируются по category, и каждый group добавляется к HashSet, который сопоставляется с каждой категорией. Поскольку наборы не допускают дублирования, дубликаты групп не будут созданы ни для одной категории. Затем, отличное количество групп - это размер каждого набора.

Для # 3 я бы снова использовал Collectors.groupingBy вместе с Collectors.counting, но я бы использовал составной ключ для группировки по:

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

Это группирует Resource элементов по category и group, , считая , сколько из них принадлежит каждой (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())));
0 голосов
/ 10 октября 2019

Спасибо 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());
        }
...