Stream分组

发布时间:2023-05-18

Java Stream 分组操作示例

一、Stream分组求和

使用 Collectors.groupingByCollectors.summingDouble 对 List 进行分组后求和。

/**
 * 求和
 */
public void sum(){
    List<Data> dataList = getDataList();
    Map<String, Double> map = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType, Collectors.summingDouble(Data::getValue)));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1),
    new Data("B", 2),
    new Data("A", 3),
    new Data("B", 4),
    new Data("C", 5)
);

结果:

Map<String, Double> result = {
    "A": 4.0,
    "B": 6.0,
    "C": 5.0
}

二、Stream分组前十

使用 Collectors.groupingByStream.sorted().limit() 获取每组的前10个数据。

/**
 * 分组前十
 */
public void top(){
    List<Data> dataList = getDataList();
    Map<String, List<Data>> groups = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType));
    Map<String, List<Data>> result = new HashMap<>();
    groups.forEach((k, v) -> {
        List<Data> top = v.stream()
            .sorted(Comparator.comparing(Data::getValue).reversed())
            .limit(10)
            .collect(Collectors.toList());
        result.put(k, top);
    });
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1),
    new Data("B", 2),
    new Data("A", 3),
    new Data("B", 4),
    new Data("C", 5)
);

结果:

Map<String, List<Data>> result = {
    "A": [{type: "A", value: 3}, {type: "A", value: 1}],
    "B": [{type: "B", value: 4}, {type: "B", value: 2}],
    "C": [{type: "C", value: 5}]
}

三、Stream分组拼接

使用 Collectors.groupingByCollectors.mapping + Collectors.joining 对分组后的属性进行拼接。

/**
 * 字符串拼接
 */
public void join(){
    List<Data> dataList = getDataList();
    Map<String, String> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType, 
            Collectors.mapping(Data::getName, Collectors.joining(","))));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1, "A1"),
    new Data("B", 2, "B1"),
    new Data("A", 3, "A2"),
    new Data("B", 4, "B2"),
    new Data("C", 5, "C1")
);

结果:

Map<String, String> result = {
    "A": "A1,A2",
    "B": "B1,B2",
    "C": "C1"
}

四、Map转List Stream

使用 flatMap 将 Map 转换为 List,并在转换过程中添加额外属性。

/**
 * Map转List
 */
public void mapToList(){
    Map<String, List<Data>> map = getMap();
    List<Data> result = map.entrySet()
        .stream()
        .flatMap(entry -> entry.getValue().stream()
            .peek(data -> data.setType(entry.getKey())))
        .collect(Collectors.toList());
}

示例数据:

Map<String, List<Data>> map = {
    "A": [{value: 1}, {value: 2}],
    "B": [{value: 3}, {value: 4}]
}

结果:

List<Data> result = [
    {type: "A", value: 1},
    {type: "A", value: 2},
    {type: "B", value: 3},
    {type: "B", value: 4}
]

五、Stream分组List

使用 Collectors.groupingBy 对 List 进行分组,返回分组后的 List。

/**
 * 分组List
 */
public void groupList(){
    List<Data> dataList = getDataList();
    Map<String, List<Data>> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1),
    new Data("B", 2),
    new Data("A", 3),
    new Data("B", 4),
    new Data("C", 5)
);

结果:

Map<String, List<Data>> result = {
    "A": [{type: "A", value: 1}, {type: "A", value: 3}],
    "B": [{type: "B", value: 2}, {type: "B", value: 4}],
    "C": [{type: "C", value: 5}]
}

六、Stream分组并排序

使用 Collectors.collectingAndThen 对分组后的 List 进行排序。

/**
 * 分组排序
 */
public void sort(){
    List<Data> dataList = getDataList();
    Map<String, List<Data>> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType,
            Collectors.collectingAndThen(Collectors.toList(), list -> {
                list.sort(Comparator.comparingDouble(Data::getValue));
                return list;
            })));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1),
    new Data("B", 2),
    new Data("A", 3),
    new Data("B", 4),
    new Data("C", 5)
);

结果:

Map<String, List<Data>> result = {
    "A": [{type: "A", value: 1}, {type: "A", value: 3}],
    "B": [{type: "B", value: 2}, {type: "B", value: 4}],
    "C": [{type: "C", value: 5}]
}

七、Stream分组计数

使用 Collectors.counting() 对每组数据进行计数。

/**
 * 统计数量
 */
public void count(){
    List<Data> dataList = getDataList();
    Map<String, Long> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType, Collectors.counting()));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1),
    new Data("B", 2),
    new Data("A", 3),
    new Data("B", 4),
    new Data("C", 5)
);

结果:

Map<String, Long> result = {
    "A": 2,
    "B": 2,
    "C": 1
}

八、Stream分组统计数量(带求和)

使用 Collectors.summingInt 对每组数据的数量属性进行求和。

/**
 * 统计数量
 */
public void count(){
    List<Data> dataList = getDataList();
    Map<String, Integer> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType,
            Collectors.summingInt(Data::getValue)));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1),
    new Data("B", 2),
    new Data("A", 3),
    new Data("B", 4),
    new Data("C", 5)
);

结果:

Map<String, Integer> result = {
    "A": 4,
    "B": 6,
    "C": 5
}

九、Stream分组求和BigDecimal

使用 Collectors.reducing 对 BigDecimal 类型进行求和。

/**
 * BigDecimal求和
 */
public void bigDecimalSumming(){
    List<Data> dataList = getDataList();
    Map<String, BigDecimal> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType,
            Collectors.mapping(Data::getValue,
                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", new BigDecimal(1)),
    new Data("B", new BigDecimal(2)),
    new Data("A", new BigDecimal(3)),
    new Data("B", new BigDecimal(4)),
    new Data("C", new BigDecimal(5))
);

结果:

Map<String, BigDecimal> result = {
    "A": new BigDecimal(4),
    "B": new BigDecimal(6),
    "C": new BigDecimal(5)
}

十、Stream分组后对List处理选取

使用 Collectors.collectingAndThen 对分组后的 List 进行随机选取。

/**
 * 分组取值
 */
public void groupSample(){
    List<Data> dataList = getDataList();
    int size = 2;
    Map<String, List<String>> result = dataList.stream()
        .collect(Collectors.groupingBy(Data::getType,
            Collectors.collectingAndThen(Collectors.toList(), list -> {
                Collections.shuffle(list);
                return list.stream()
                    .limit(size)
                    .map(Data::getName)
                    .collect(Collectors.toList());
            })));
}

示例数据:

List<Data> dataList = Arrays.asList(
    new Data("A", 1, "A1"),
    new Data("B", 2, "B1"),
    new Data("A", 3, "A2"),
    new Data("B", 4, "B2"),
    new Data("C", 5)
);

结果:

Map<String, List<String>> result = {
    "A": ["A2", "A1"],
    "B": ["B2", "B1"],
    "C": ["C1"]
}