基于复杂匹配键的多个属性分组和聚合

Gan*_*der 5 java collections java-8 java-stream

我是 Java 新手,正在解决一个问题,我需要根据下面的匹配键对集合进行分组和聚合,这个键是来自下面提到的类的属性的组合。

class MyKey {    
      String planYearMonth;
      String carSeries;
      String weekNo;
      String factoryCode;
      String lineClass;
      String frameSortCode;
      String ocfClassificationCode;
      String locationIdentificationCode;
      String carGroup;
      //setters & getters
      //equals & hashcode
    }

public class OCFIdentificationInfo {    
    private String frameSortCode;   
    private String ocfClassificationCode;   
    private String locationIdentificationCode;  
    private String carGroup;    
    private String frameCode;   
    //getters 
    //setters
    //hashCode
    //equals
    //toString
}

public class DailyOCF { 
    private String planYearMonth;   
    private String carSeries;   
    private String weekNo;  
    private String day; 
    private String factoryCode; 
    private String lineClass;   
    private OCFIdentificationInfo ocfInfo   
    private int maxQty = 0; 
    private int actualQty = 0;  
    //getters 
    //setters
    //hashCode
    //equals
    //toString
}
Run Code Online (Sandbox Code Playgroud)

DailyOCF集合填充在ArrayList下面提供的示例数据中。

DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=00, ocfClassificationCode=MICRA   , locationIdentificationCode=XXX, carGroup=YYY, frameCode=00], maxQty=20, actualQty=0]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=10, ocfClassificationCode=SEDAN   , locationIdentificationCode=XXX, carGroup=YYY, frameCode=10], maxQty=20, actualQty=0]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=90, ocfClassificationCode=HDD navi, locationIdentificationCode=XXX, carGroup=YYY, frameCode=90], maxQty=3, actualQty=0]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=00, ocfClassificationCode=MICRA   , locationIdentificationCode=XXX, carGroup=YYY, frameCode=00], maxQty=20, actualQty=0]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=10, ocfClassificationCode=SEDAN   , locationIdentificationCode=XXX, carGroup=YYY, frameCode=10], maxQty=20, actualQty=0]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=60, ocfClassificationCode=GGRADE  , locationIdentificationCode=XXX, carGroup=YYY, frameCode=60], maxQty=10, actualQty=0]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=90, ocfClassificationCode=HDD navi, locationIdentificationCode=XXX, carGroup=YYY, frameCode=90], maxQty=3, actualQty=0]
Run Code Online (Sandbox Code Playgroud)

上面的列表需要根据上面提到的匹配键进行分组,分组后的列表应该如下所示。

DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=90, ocfClassificationCode=HDD navi, locationIdentificationCode=XXX, carGroup=YYY, frameCode=90], maxQty=3, actualQty=2]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=60, ocfClassificationCode=GGRADE  , locationIdentificationCode=XXX, carGroup=YYY, frameCode=60], maxQty=10, actualQty=1]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=10, ocfClassificationCode=SEDAN   , locationIdentificationCode=XXX, carGroup=YYY, frameCode=10], maxQty=20, actualQty=2]
DailyOCF [planYearMonth=201304, carSeries=K01, weekNo=17, day=, factoryCode=BBB, lineClass=1, ocfInfo=OCFIdentificationInfo [frameSortCode=00, ocfClassificationCode=MICRA   , locationIdentificationCode=XXX, carGroup=YYY, frameCode=00], maxQty=20, actualQty=2]
Run Code Online (Sandbox Code Playgroud)

actualQty申请需要汇总的基础上,匹配的密钥。

为了实现这一点,我写了下面的 java 代码但没有运气,请看一看,让我知道天气方法是否正确?

Map<MyKey, List<DailyOCF>> finalResult = dailyOCFList.stream()
  .collect(groupingBy(ocf -> new MyKey(ocf.planYearMonth, ocf.carSeries, ocf.weekNo, ocf.factoryCode,
      ocf.lineClass, ocf.ocfInfo.frameSortCode, ocf.ocfInfo.ocfClassificationCode,
      ocf.ocfInfo.locationIdentificationCode, ocf.ocfInfo.carGroup)));
Run Code Online (Sandbox Code Playgroud)

这就是DailyOCF列表填充的方式。

OCFIdentificationInfo info = new OCFIdentificationInfo();
info.setCarGroup("YYY");
info.setFrameCode("00");
info.setFrameSortCode("00");
info.setLocationIdentificationCode("XXX");
info.setOcfClassificationCode("MICRA");

OCFIdentificationInfo info1 = new OCFIdentificationInfo();
info1.setCarGroup("YYY");
info1.setFrameCode("10");
info1.setFrameSortCode("10");
info1.setLocationIdentificationCode("XXX");
info1.setOcfClassificationCode("SEDAN");

OCFIdentificationInfo info2 = new OCFIdentificationInfo();
info2.setCarGroup("YYY");
info2.setFrameCode("90");
info2.setFrameSortCode("90");
info2.setLocationIdentificationCode("XXX");
info2.setOcfClassificationCode("HDD navi");

OCFIdentificationInfo info3 = new OCFIdentificationInfo();
info3.setCarGroup("YYY");
info3.setFrameCode("00");
info3.setFrameSortCode("00");
info3.setLocationIdentificationCode("XXX");
info3.setOcfClassificationCode("MICRA");

OCFIdentificationInfo info4 = new OCFIdentificationInfo();
info4.setCarGroup("YYY");
info4.setFrameCode("10");
info4.setFrameSortCode("10");
info4.setLocationIdentificationCode("XXX");
info4.setOcfClassificationCode("SEDAN");

OCFIdentificationInfo info5 = new OCFIdentificationInfo();
info5.setCarGroup("YYY");
info5.setFrameCode("60");
info5.setFrameSortCode("60");
info5.setLocationIdentificationCode("XXX");
info5.setOcfClassificationCode("GGRADE");

OCFIdentificationInfo info6 = new OCFIdentificationInfo();
info6.setCarGroup("YYY");
info6.setFrameCode("90");
info6.setFrameSortCode("90");
info6.setLocationIdentificationCode("XXX");
info6.setOcfClassificationCode("HDD navi");


DailyOCF dailyOCF = new DailyOCF();
dailyOCF.setPlanYearMonth("201304");
dailyOCF.setCarSeries("K01");
dailyOCF.setWeekNo("17");
dailyOCF.setDay("");
dailyOCF.setFactoryCode("BBB");
dailyOCF.setLineClass("1");
dailyOCF.setOcfInfo(info);

DailyOCF dailyOCF1 = new DailyOCF();
dailyOCF1.setPlanYearMonth("201304");
dailyOCF1.setCarSeries("K01");
dailyOCF1.setWeekNo("17");
dailyOCF1.setDay("");
dailyOCF1.setFactoryCode("BBB");
dailyOCF1.setLineClass("1");
dailyOCF1.setOcfInfo(info1);

DailyOCF dailyOCF2 = new DailyOCF();
dailyOCF2.setPlanYearMonth("201304");
dailyOCF2.setCarSeries("K01");
dailyOCF2.setWeekNo("17");
dailyOCF2.setDay("");
dailyOCF2.setFactoryCode("BBB");
dailyOCF2.setLineClass("1");
dailyOCF2.setOcfInfo(info2);

DailyOCF dailyOCF3 = new DailyOCF();
dailyOCF3.setPlanYearMonth("201304");
dailyOCF3.setCarSeries("K01");
dailyOCF3.setWeekNo("17");
dailyOCF3.setDay("");
dailyOCF3.setFactoryCode("BBB");
dailyOCF3.setLineClass("1");
dailyOCF3.setOcfInfo(info3);

DailyOCF dailyOCF4 = new DailyOCF();
dailyOCF4.setPlanYearMonth("201304");
dailyOCF4.setCarSeries("K01");
dailyOCF4.setWeekNo("17");
dailyOCF4.setDay("");
dailyOCF4.setFactoryCode("BBB");
dailyOCF4.setLineClass("1");
dailyOCF4.setOcfInfo(info4);


DailyOCF dailyOCF5 = new DailyOCF();
dailyOCF5.setPlanYearMonth("201304");
dailyOCF5.setCarSeries("K01");
dailyOCF5.setWeekNo("17");
dailyOCF5.setDay("");
dailyOCF5.setFactoryCode("BBB");
dailyOCF5.setLineClass("1");
dailyOCF5.setOcfInfo(info5);


DailyOCF dailyOCF6 = new DailyOCF();
dailyOCF6.setPlanYearMonth("201304");
dailyOCF6.setCarSeries("K01");
dailyOCF6.setWeekNo("17");
dailyOCF6.setDay("");
dailyOCF6.setFactoryCode("BBB");
dailyOCF6.setLineClass("1");
dailyOCF6.setOcfInfo(info6);


List<DailyOCF> dailyOCFList = new ArrayList<DailyOCF>();
dailyOCFList.add(dailyOCF);
dailyOCFList.add(dailyOCF1);
dailyOCFList.add(dailyOCF2);
dailyOCFList.add(dailyOCF3);
dailyOCFList.add(dailyOCF4);
dailyOCFList.add(dailyOCF5);
dailyOCFList.add(dailyOCF6);
Run Code Online (Sandbox Code Playgroud)

Nam*_*man 2

Collectors.toMap在这种情况下你可以使用:

Map<MyKey, DailyOCF> finalResult = dailyOCFList.stream()
        .collect(Collectors.toMap(ocf -> new MyKey(ocf.planYearMonth, ocf.carSeries, ocf.weekNo, 
                        ocf.factoryCode, ocf.lineClass, ocf.ocfInfo.frameSortCode, 
                        ocf.ocfInfo.ocfClassificationCode, ocf.ocfInfo.locationIdentificationCode, 
                        ocf.ocfInfo.carGroup), Function.identity(), this::mergeDailyOCF));

List<DailyOCF> res = new ArrayList<>(finalResult.values());
Run Code Online (Sandbox Code Playgroud)

使用的底层方法如下所示:

DailyOCF mergeDailyOCF(DailyOCF dailyOCF1, DailyOCF dailyOCF2) {
    return new DailyOCF(dailyOCF1.planYearMonth, dailyOCF1.carSeries, dailyOCF1.weekNo,
            dailyOCF1.factoryCode, dailyOCF1.lineClass, dailyOCF1.day,
            mergeOCFInfo(dailyOCF1.ocfInfo, dailyOCF2.ocfInfo), Math.max(dailyOCF1.maxQty, dailyOCF2.maxQty),
            Integer.sum(dailyOCF1.actualQty, dailyOCF2.actualQty)); // assign 'actualQty = 1' as default
}

OCFIdentificationInfo mergeOCFInfo(OCFIdentificationInfo info1, OCFIdentificationInfo info2) {
    return info1;
    // implement custom logic if required
    // return new OCFIdentificationInfo(info1.frameSortCode, info1.ocfClassificationCode,
    // info1.locationIdentificationCode, info1.carGroup, info1.frameCode);
}
Run Code Online (Sandbox Code Playgroud)