根据匹配属性将对象分组到 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
对象内基于 regionId
和 regionName
进行分组。
对于 regionId
和 regionName
的组合,我们可以在目标对象中包含 List
个 countries
。
我在数据库中输入了这 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());
我有类类似于:
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
对象内基于 regionId
和 regionName
进行分组。
对于 regionId
和 regionName
的组合,我们可以在目标对象中包含 List
个 countries
。
我在数据库中输入了这 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());