java 8 группировка с четким счетом - PullRequest
4 голосов
/ 12 октября 2019
SELECT Count(1) AS total,
          'hello' AS filter,
          field1 AS field1,
          Count(DISTINCT field2) AS total_field2
   FROM table
   WHERE field = true
     AND status = 'ok'
      GROUP  BY field1

Сомневается, как сделать карту, используя java8 для хранения следующего результата. Ключ карты должен быть полем field1, а значение карты должно быть total_field2 полем.

То есть мне нужно сгруппировать свой список, используя поле field1 и поле count count2

Дляобщее поле у ​​меня есть

myList.stream().collect(Collectors.groupingBy(MyObject::getField1, Collectors.counting())) 
// this is just counting the records grouped by field1

Мой результат правильный total_field1: {4 = 55, 6 = 31}

Для поля 2 мне нужно что-товот так, но он просто дает мне запись

myList.stream().filter(distinctByKey(MyObject::getField2))
.collect(Collectors.groupingBy(MyObject::getField1, Collectors.counting()));

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

Результат total_Field2: {4 = 31}

должен вернуть мне 2 примера записи total_Field2:{4 = 31, 6 = 31}

Пример @ Naman

public static <T, A, R> Collector<T, ?, R> filtering(
        Predicate<? super T> predicate, Collector<? super T, A, R> downstream) {

        BiConsumer<A, ? super T> accumulator = downstream.accumulator();
        return Collector.of(downstream.supplier(),
            (r, t) -> { if(predicate.test(t)) accumulator.accept(r, t); },
            downstream.combiner(), downstream.finisher(),
            downstream.characteristics().toArray(new Collector.Characteristics[0]));
    }

myList.stream().collect(Collectors.groupingBy(MyObject::getField1, filtering(distinctByKey(MyObject::getField2), Collectors.counting())));

Ответы [ 3 ]

3 голосов
/ 12 октября 2019

На самом деле я использовал Set для устранения дубликатов и Collectors.collectingAndThen для получения размера

Map<String, Integer> res =  list.stream()
                                .collect(Collectors.groupingBy(MyObject::getField1, 
                                        Collectors.mapping(MyObject::getField2, 
                                            Collectors.collectingAndThen(Collectors.toSet(), set->set.size()))));

В соответствии с предложением @Naman вы также можете использовать ссылку на метод Set::size

Collectors.collectingAndThen(Collectors.toSet(), Set::size))));
2 голосов
/ 12 октября 2019

Альтернатива Ответ Дэдпула состоит в подсчете distinctByKey после группировкиBy field1 при сопоставлении с записями и последующем сборе в Map как:

Map<String, Long> r = myList.stream()
        .collect(Collectors.groupingBy(MyObject::getField1))
        .entrySet().stream()
        .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(),
                e.getValue().stream().filter(distinctByKey(MyObject::getField2)).count()))
        .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));

Если бы вы работали на Java-9 или выше, вы могли бы использовать Collectors.filtering в качестве downstream с Predicate, определенным с помощью утилиты distinctByKey, такой как:

Map<String, Long> result = myList.stream()
        .collect(Collectors.groupingBy(MyObject::getField1,
                Collectors.filtering(distinctByKey(MyObject::getField2),
                        Collectors.counting())));


Примечание : два вышеупомянутых подхода весьма различны, хотя первый объединяет все элементы списка по одному полю (field1), а затем в каждой подгруппе находит отдельный счетчик по другому определенному полю (field2).

С другой стороны, последний группирует все отдельные элементы по ключу (field2), а затем группирует этидругим ключом (field1) с уменьшением счета.

0 голосов
/ 16 октября 2019

Вы можете попробовать это:

myList.stream().map(obj -> Pair.of(obj.getField1(), obj.getField2())
      .distinct()
      .collect(groupingBy(Pair::getLeft, counting()));
...