如何使用集合计算列表中每个元素的出现次数?

3
假设我有一个看起来像这样的 List<Set<String>>
[A,B,C,D]
[B,C,D,E]
[C,D,E,F]
[D,E,F,G]

如果我想在List<Set<String>>中的每个Set<String>中使用每个值(A,B,C,D,E,F,G)并通过映射计算它们的出现次数,有什么好的方法可以实现吗? 我想让输出看起来像这样:
A: 1
B: 2
C: 3
D: 4
E: 3
F: 2
G: 1
3个回答

4

将列表展平为单个流,然后使用groupingBy收集器。

  • 首先,将列表转化为流。这会创建一系列较小的流。
  • 接下来,需要对它们进行流处理。但是您不想要4个字母流,而是想要一个16个字母(或所有集合的总和)的流,这就是flatMap所做的工作。它将多个流展平为一个流。
  • 然后,您需要进行频率统计。因此,您需要使用字母本身作为键将字母分组。默认情况下,groupingBy会创建一个列表并将冲突(与重复键相关联的值)放在列表中。
  • 但是您不想这样,因此Collectors.counting()表示如果您看到另一个已存在的键,请只保留计数并将值更新为1。因此,您正在计算键的出现次数。
List<Set<String>> list = List.of(Set.of("A", "B", "C", "D"),
        Set.of("B", "C", "D", "E"),
        Set.of("C", "D", "E", "F"),
        Set.of("D", "E", "F", "G"));

Map<String, Long> freq =
        list.stream().flatMap(Set::stream).collect(Collectors
                .groupingBy(a -> a, Collectors.counting()));

freq.entrySet().forEach(System.out::println);

打印

A=1
B=2
C=3
D=4
E=3
F=2
G=1

这是一个默认 groupingBy 行为的简单示例。它根据除以 10 的余数将值放入列表中。 IntStream 生成一个 int原始类型 流,因此需要将它们转换为对象(在这种情况下为 Integer)才能进行收集。
Map<Integer, List<Integer>> remainders =
        IntStream.range(0, 100).mapToObj(Integer::valueOf)
                .collect(Collectors.groupingBy(n -> n % 10));

remainders.entrySet().forEach(System.out::println); 

打印

0=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
1=[1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
2=[2, 12, 22, 32, 42, 52, 62, 72, 82, 92]
3=[3, 13, 23, 33, 43, 53, 63, 73, 83, 93]
4=[4, 14, 24, 34, 44, 54, 64, 74, 84, 94]
5=[5, 15, 25, 35, 45, 55, 65, 75, 85, 95]
6=[6, 16, 26, 36, 46, 56, 66, 76, 86, 96]
7=[7, 17, 27, 37, 47, 57, 67, 77, 87, 97]
8=[8, 18, 28, 38, 48, 58, 68, 78, 88, 98]
9=[9, 19, 29, 39, 49, 59, 69, 79, 89, 99]

运行完美,但您能否帮我详细说明一下您在.collect()部分实现的算法? - Mint

3
        List<Set<String>> input = new ArrayList<>();
        input.add(Set.of("A", "B", "C", "D"));
        input.add(Set.of("B", "C", "D", "E"));
        input.add(Set.of("C", "D", "E", "F"));
        input.add(Set.of("D", "E", "F", "G"));

        input.stream()
                .flatMap(Collection::stream)
                .collect(groupingBy(Function.identity(), counting()))
                .entrySet()
                .forEach(System.out::println);

导入

import java.util.*;
import java.util.function.Function;

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

1
使用Stream API时,应该使用flatMap来获取字符串流中的内部集合,然后构建一个频率映射。
        
List<Set<String>> data = Arrays.asList(
    Set.of("A", "B", "C", "D"),
    Set.of("B", "C", "D", "E"),
    Set.of("C", "D", "E", "F"),
    Set.of("D", "E", "F", "G")
);
        
data.stream()
    .flatMap(Set::stream)
    .collect(Collectors.toMap(s -> s, s -> 1, Integer::sum, LinkedHashMap::new))
    .entrySet()
    .forEach(System.out::println);

输出:

A=1
B=2
C=3
D=4
E=3
F=2
G=1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接