java 8 个不同计数的分组依据
java 8 grouping by with distinct count
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 和计数字段 field2 对我的列表进行分组
对于我的总字段
myList.stream().collect(Collectors.groupingBy(MyObject::getField1, Collectors.counting()))
// this is just counting the records grouped by field1
我的结果是正确的total_field1: {4=55, 6=31}
对于 field2,我需要这样的东西,但它只是给我一个记录
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}
应该 return 我 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())));
的替代方法是在映射到条目时在分组 field1
之后计算 distinctByKey
,然后最终收集到 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
,并使用实用程序 [=12= 定义 Predicate
] 例如:
Map<String, Long> result = myList.stream()
.collect(Collectors.groupingBy(MyObject::getField1,
Collectors.filtering(distinctByKey(MyObject::getField2),
Collectors.counting())));
注意:虽然以上两种方法有很大不同,前者将所有列表项按一个字段(field1
)分组,然后在每个子组中找到一个另一个特定字段的非重复计数 (field2
).
另一方面,后者按键(field2
)对所有不同的项目进行分组,然后按另一个键(field1
)对这些项目进行分组,并减少计数。
实际上我使用 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))));
你可以试试这个:
myList.stream().map(obj -> Pair.of(obj.getField1(), obj.getField2()))
.distinct()
.collect(Collectors.groupingBy(Pair::getLeft, counting()));
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 和计数字段 field2 对我的列表进行分组
对于我的总字段
myList.stream().collect(Collectors.groupingBy(MyObject::getField1, Collectors.counting()))
// this is just counting the records grouped by field1
我的结果是正确的total_field1: {4=55, 6=31}
对于 field2,我需要这样的东西,但它只是给我一个记录
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}
应该 return 我 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())));
field1
之后计算 distinctByKey
,然后最终收集到 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
,并使用实用程序 [=12= 定义 Predicate
] 例如:
Map<String, Long> result = myList.stream()
.collect(Collectors.groupingBy(MyObject::getField1,
Collectors.filtering(distinctByKey(MyObject::getField2),
Collectors.counting())));
注意:虽然以上两种方法有很大不同,前者将所有列表项按一个字段(field1
)分组,然后在每个子组中找到一个另一个特定字段的非重复计数 (field2
).
另一方面,后者按键(field2
)对所有不同的项目进行分组,然后按另一个键(field1
)对这些项目进行分组,并减少计数。
实际上我使用 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))));
你可以试试这个:
myList.stream().map(obj -> Pair.of(obj.getField1(), obj.getField2()))
.distinct()
.collect(Collectors.groupingBy(Pair::getLeft, counting()));