利用Stream API对List集合进行分组求和统计(2种方式)

一、根据String类型字段分组,求BigDecimal类型的和

1.原始数据及需求

需求:发货地和收货地相同的数据,合并这两项,并计算其他两项的数据之和

拿到的原始数据如下图所示:

image

2.利用StreamAPI处理List集合

代码如下:

    @Override
    public Map<String, Object> countCarLine(String begin, String end) {
        // 线路统计
        List<CarLineVO> carLineVOS = dashboardMapper.countCarLine(begin, end);

		// 接收处理后的数据
        List<CarLineVO> newCarLineVOs = new ArrayList<>();
        // 数据分组统计处理
        carLineVOS.parallelStream()
                .collect(Collectors.groupingBy(item -> (item .getDeliverAddress() + item .getCollectAddress()), Collectors.toList()))
                .forEach((id, transfer) -> {
                    transfer.stream()
                            .reduce((a, b) -> new CarLineVO(a.getDeliverAddress(), a.getCollectAddress(), a.getCollectNetWeight().add(b.getCollectNetWeight()), a.getTotalFreightPrice().add(b.getTotalFreightPrice())))
                            .ifPresent(newCarLineVOs::add);
                });

        Map<String, Object> map = new HashMap<>();
        map.put("carLine", newCarLineVOs);
        return map;
    }

3.处理后得到符合需求的数据

处理后的数据:

image

4.实体类

CarLineVO类:

/**
 * @Author: Ron
 * @Create: 2020 10:14
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CarLineVO {

    private String deliverAddress;

    private String collectAddress;

    private BigDecimal collectNetWeight;

    private BigDecimal totalFreightPrice;
}

实体类使用lombok插件

二、根据String类型字段分组,求int类型的和

1.实体类

package com.qs.modules.formMaterial.model;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.qs.db.base.model.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * 申请单和物料中间表
 *
 * @author Charles
 * @since 2021/09/30
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@TableName("form_material")
@ApiModel(value="申请单和物料中间表", description="申请单和物料中间表")
public class FormMaterial extends BaseModel {
    private static final long serialVersionUID = 1L;

    /**
     * 主键id
     */
    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private String id;

    /**
     * 申请单id
     */
    @ApiModelProperty(value = "申请单id")
    private String applicationFormId;

    /**
     * 申请物料的id
     */
    @ApiModelProperty(value = "申请物料的id")
    private String materialId;

    /**
     * 申请物料的数量
     */
    @ApiModelProperty(value = "申请物料的数量")
    private int materialCount;

    /**
     * 取出的物料总数
     */
    @ApiModelProperty(value = "取出的物料总数")
   private int takeTotalCount;

    /**
     * 剩余物料数量
     */
    @ApiModelProperty(value = "剩余物料数量")
   private int remainingCount;


    /**
     * 此物料是否被领取完:0即未领取完,1即领取完
     */
    @ApiModelProperty(value = "此物料是否被领取完")
    private String materialFlag;

    @TableField(exist = false)
    private String materialNumber;

    @TableField(exist = false)
    private String materialName;

    /**
     * 传入的查询条件:物料数量
     */
    @TableField(exist = false)
    private String queryMaterialCount;

    /**
     * 入参
     */
    public static final String APPLICATION_FORM_ID = "application_form_id";
    public static final String MATERIAL_COUNT = "material_count";

}

2.需求

传过来的数据是这样的,物料id-materialId相同的话,物料数量求和materialCount

[
	{
		"materialId": "1453637685838372866",
		"materialCount": "15"
	},
	{
		"materialId": "1453638065183809538",
		"materialCount": "21"
	},
	{
		"materialId": "1482879355628838914",
		"materialCount": "8"
	}
]

3.Stream处理

        // 申请的重复物料信息,根据物料id,申请的物料数量求和合并成一条数据
		// formMaterialList就是来源的集合
        List<FormMaterial> newList = new ArrayList<>();
        formMaterialList.parallelStream()
            .collect(Collectors.groupingBy(FormMaterial::getMaterialId, Collectors.toList()))
            .forEach(
                (materialId, list) ->
                    list.stream()
                        .reduce(
                            (a, b) ->
                                new FormMaterial()
                                    .setMaterialId(a.getMaterialId())
                                    .setMaterialCount(a.getMaterialCount() + b.getMaterialCount()))
                        .ifPresent(newList::add));

三、总结

感觉和for循环差不多,流式运算里也是带了.forEach的方法了。

posted @ 2022-02-16 15:31  Charles博客  阅读(7418)  评论(0编辑  收藏  举报