根据匹配属性将对象分组到 java 8 或 java 11 中的列表中

group objects based on matching properties into list in java 8 or java 11

我有类类似于:

class Response {
    Source source;
    Target target;
}

class Source {
    Long sourceId;
    String sourceName;
}

class Target {
    Long regionId;
    String regionName;
    Long countryId;
    String countryName;
}

在响应中,source(sourceId,sourceName) 对于不同的目标对象可能是相同的。 同样,我也想在 Target 对象内基于 regionIdregionName 进行分组。 对于 regionIdregionName 的组合,我们可以在目标对象中包含 Listcountries

我在数据库中输入了这 6 个属性 sourceId, sourceName, targetId, targetName,countryId,countryName。我可以在多行上设置相同的 sourceId, sourceName,但 target 将始终不同。

我想将所有目标对象分组到源相同的列表中。

我有响应对象列表,我正在尝试对其执行 stream() 操作,例如:

List<Response> responses; // set up the input list

List<FinalResponse> finalResponseLst = responses.stream()
    .collect(Collectors.groupingBy(
        Response::getSource,
        Collectors.mapping(Response::getTarget, Collectors.toList())
    )) 
    .entrySet()
    .stream() 
    .map(e -> new FinalResponse(e.getKey(), e.getValue()))
    .collect(Collectors.toList());

这给了我 Source 及其各自的 Target 对象。但是如何根据地区对目标对象内的国家进行分组呢?如何为单个 Target 对象创建具有相同区域的国家/地区列表。 所以我的最终输出 JSON 看起来像:

Response": { 
    "Source":       {  
        "sourceId":       "100",   
        "sourceName":      "source1",    
    },
    "Targets": [
    {
    "TargetRegion":{//grouping target objects with same regions
        "regionId":       "100",   
        "regionName":      "APAC",          
    }, 
    "TargetCountries":[{
        "countryId":       "1",   
        "countryName":      "USA",   
    },
    {
        "targetId":       "2",   
        "targetName":      "China",   
    },
    {
        "targetId":       "3",   
        "targetName":     "Brazil"   
    }
    ]
    },
    {
    "TargetRegion":{//grouping target objects with same regions
       
        "regionId":       "200",   
        "regionName":      "ASPAC",         
    }, 
    "TargetCountries":[{
        "countryId":       "11",   
        "countryName":      "Japan",   
    },
    {
        "targetId":       "22",   
        "targetName":      "Combodia",   
    },
    {
        "targetId":       "33",   
        "targetName":     "Thailand"   
    }
    ]
    }

    ]
}

您应该只添加额外的分组并确保存在适当的 POJO 类:

  • POJO 类:
@Data
@AllArgsConstructor
class Region {
    Long regionId;
    String regionName;
}

@Data
@AllArgsConstructor
class Country {
    Long countryId;
    String countryName;
}

@Data
@AllArgsConstructor
class RegionCountries {
    private Region targetRegion;
    private List<Country> targetCountries;
}

@Data
@AllArgsConstructor
class FinalResponse {
    Source source;
    List<RegionCountries> targets;
}

那么采集可以按如下方式实现。
如果输入列表 responses 已排序并且需要维护此顺序,则应将 LinkedHashMap::new 供应商应用于所有地图:

List<FinalResponse> f = responses.stream()
        .collect(Collectors.groupingBy(
                Response::getSource,
                LinkedHashMap::new, // if pre-sorted by source
                Collectors.groupingBy(
                        r -> new Region(
                            r.getTarget().getRegionId(),
                            r.getTarget().getRegionName()
                        ),
                        LinkedHashMap::new, // if pre-sorted by region
                        Collectors.mapping(r -> new Country(
                                r.getTarget().getCountryId(), 
                                r.getTarget().getCountryName()
                            ),
                            Collectors.toList()
                        )
                )
        )) // Map<Source, Map<Region, List<Country>>>
        .entrySet()
        .stream()
        .map(e -> new FinalResponse(
                e.getKey(),
                e.getValue().entrySet()
                 .stream()
                 .map(re -> new RegionCountries(re.getKey(), re.getValue()))
                 .collect(Collectors.toList()) // List<RegionCountries>
        ))
        .collect(Collectors.toList());

如果输入未排序或现有排序需要更改,则在收集地图的中间地图时,可能会在收集结果列表之前根据需要重新排序其条目流(类似于收集 RegionCountries):

       // ... collecting the intermediate map as above
        )) // Map<Source, Map<Region, List<Country>>>
        .entrySet()
        .stream()
        .sorted(Map.Entry.comparingByKey(
             Comparator.comparingLong(Source::getSourceId)
        ))
        .map(e -> new FinalResponse(
                e.getKey(),
                e.getValue().entrySet()
                 .stream()
                 .sorted(Map.Entry.comparingByKey(
                     Comparator.comparingLong(Region::getRegionId)
                 ))
                 .map(re -> new RegionCountries(re.getKey(), re.getValue()))
                 .collect(Collectors.toList()) // List<RegionCountries>
        ))
        .collect(Collectors.toList());