使用 java 流的复杂对象组列表
group list of complex object using java stream
我有一个 gprsEvents 列表,其中列表中的每个元素都是一个 Map ,如下所示。我需要:
{
"events":[
{
"localTimeStamp":"20170523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"1",
"2"
],
"index":"1",
"dataVolumeIncoming":"400000",
"dataVolumeOutgoing":"27600",
"callChargingId":"4100853125",
},
{
"localTimeStamp":"20190523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"2",
"4"
],
"index":"2",
"dataVolumeIncoming":"300000",
"dataVolumeOutgoing":"47600",
"callChargingId":"4100853125",
},
{
"localTimeStamp":"20180523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"1",
"2"
],
"index":"7",
"dataVolumeIncoming":"100000",
"dataVolumeOutgoing":"17600",
"callChargingId":"5100853125",
}
]
}
- 按字段“callChargingId”对列表中的元素进行分组。
- 分组的结果应该是一个 Map,其中的键是“callChargingIds”,是一个单一的元素,其中每个字段都包含一组字段作为分组的结果。结果应该如下所示:
{
"5100853125":[
{
"localTimeStamp":"20180523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"1",
"2"
],
"index":"7",
"dataVolumeIncoming":"100000",
"dataVolumeOutgoing":"17600"
}
],
"4100853125":[
{
"localTimeStamp":[
"20170523113305",
"20190523113305"
],
"serviceCode":"GPRS",
"recEntityCode":[
[
"1",
"2"
],
[
"2",
"4"
]
],
"index":[
"1",
"2"
],
"dataVolumeIncoming":"700000",
"dataVolumeOutgoing":"75200"
}
]
}
对于某些字段,分组的结果应该是一个列表(timeStamp、recEntityCode 和索引),而在其他字段中,结果应该是总和(dataVolumeIncoming 和 dataVolumeOutgoing
我开始考虑使用java 8流(groupingBy):
gprsEvents.stream().collect(Collectors.groupingBy(地图 -> map.get("callChargingId").toString()))
我现在坚持要获得合适的结果,特别是在一个 Map 和上述字段的列表或总和中获得结果...
这里的关键点是实现 BinaryOperator<U> mergeFunction
对象,它将完成最复杂的部分:合并两个 Map
实例。我建议使用带有 3 个参数的方法:toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator mergeFunction):
keyMapper
- callChargingId
值,
valueMapper
- Map
实例
mergeFunction
- 合并将合并两个 BinaryOperator<Map<String, Object>>
类型的实例
简单的实现可能如下所示:
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.type.MapType;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
public class JsonTypeInfoApp {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
JsonMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.build();
MapType jsonType = mapper.getTypeFactory().constructMapType(Map.class, String.class, List.class);
Map<String, List<Map<String, Object>>> response = mapper.readValue(jsonFile, jsonType);
List<Map<String, Object>> gprsEvents = response.get("events");
Map<Object, Map<String, Object>> result = gprsEvents.stream()
.collect(Collectors.toMap(
map -> map.get("callChargingId"),
map -> map,
new EventMerger()));
mapper.writeValue(System.out, result);
}
}
class EventMerger implements BinaryOperator<Map<String, Object>> {
@Override
public Map<String, Object> apply(Map<String, Object> map0, Map<String, Object> map1) {
map1.forEach((secondKey, secondValue) -> {
map0.compute(secondKey, (key, value) -> {
if (value == null) {
return secondValue;
} else if (value instanceof Set) {
Set<Object> values = (Set<Object>) value;
values.add(secondValue);
return values;
}
Set<Object> values = new HashSet<>();
values.add(value);
values.add(secondValue);
return values;
});
});
return map0;
}
}
以上代码打印:
{
"4100853125" : {
"localTimeStamp" : [ "20170523113305", "20190523113305" ],
"serviceCode" : [ "GPRS" ],
"recEntityCode" : [ [ "1", "2" ], [ "2", "4" ] ],
"index" : [ "1", "2" ],
"dataVolumeOutgoing" : [ "47600", "27600" ],
"callChargingId" : [ "4100853125" ],
"dataVolumeIncoming" : [ "400000", "300000" ]
},
"5100853125" : {
"localTimeStamp" : "20180523113305",
"serviceCode" : "GPRS",
"recEntityCode" : [ "1", "2" ],
"index" : "7",
"dataVolumeIncoming" : "100000",
"dataVolumeOutgoing" : "17600",
"callChargingId" : "5100853125"
}
}
我有一个 gprsEvents 列表,其中列表中的每个元素都是一个 Map
{
"events":[
{
"localTimeStamp":"20170523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"1",
"2"
],
"index":"1",
"dataVolumeIncoming":"400000",
"dataVolumeOutgoing":"27600",
"callChargingId":"4100853125",
},
{
"localTimeStamp":"20190523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"2",
"4"
],
"index":"2",
"dataVolumeIncoming":"300000",
"dataVolumeOutgoing":"47600",
"callChargingId":"4100853125",
},
{
"localTimeStamp":"20180523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"1",
"2"
],
"index":"7",
"dataVolumeIncoming":"100000",
"dataVolumeOutgoing":"17600",
"callChargingId":"5100853125",
}
]
}
- 按字段“callChargingId”对列表中的元素进行分组。
- 分组的结果应该是一个 Map,其中的键是“callChargingIds”,是一个单一的元素,其中每个字段都包含一组字段作为分组的结果。结果应该如下所示:
{
"5100853125":[
{
"localTimeStamp":"20180523113305",
"serviceCode":"GPRS",
"recEntityCode":[
"1",
"2"
],
"index":"7",
"dataVolumeIncoming":"100000",
"dataVolumeOutgoing":"17600"
}
],
"4100853125":[
{
"localTimeStamp":[
"20170523113305",
"20190523113305"
],
"serviceCode":"GPRS",
"recEntityCode":[
[
"1",
"2"
],
[
"2",
"4"
]
],
"index":[
"1",
"2"
],
"dataVolumeIncoming":"700000",
"dataVolumeOutgoing":"75200"
}
]
}
对于某些字段,分组的结果应该是一个列表(timeStamp、recEntityCode 和索引),而在其他字段中,结果应该是总和(dataVolumeIncoming 和 dataVolumeOutgoing
我开始考虑使用java 8流(groupingBy): gprsEvents.stream().collect(Collectors.groupingBy(地图 -> map.get("callChargingId").toString()))
我现在坚持要获得合适的结果,特别是在一个 Map 和上述字段的列表或总和中获得结果...
这里的关键点是实现 BinaryOperator<U> mergeFunction
对象,它将完成最复杂的部分:合并两个 Map
实例。我建议使用带有 3 个参数的方法:toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator mergeFunction):
keyMapper
-callChargingId
值,valueMapper
-Map
实例mergeFunction
- 合并将合并两个BinaryOperator<Map<String, Object>>
类型的实例
简单的实现可能如下所示:
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.type.MapType;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
public class JsonTypeInfoApp {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
JsonMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.build();
MapType jsonType = mapper.getTypeFactory().constructMapType(Map.class, String.class, List.class);
Map<String, List<Map<String, Object>>> response = mapper.readValue(jsonFile, jsonType);
List<Map<String, Object>> gprsEvents = response.get("events");
Map<Object, Map<String, Object>> result = gprsEvents.stream()
.collect(Collectors.toMap(
map -> map.get("callChargingId"),
map -> map,
new EventMerger()));
mapper.writeValue(System.out, result);
}
}
class EventMerger implements BinaryOperator<Map<String, Object>> {
@Override
public Map<String, Object> apply(Map<String, Object> map0, Map<String, Object> map1) {
map1.forEach((secondKey, secondValue) -> {
map0.compute(secondKey, (key, value) -> {
if (value == null) {
return secondValue;
} else if (value instanceof Set) {
Set<Object> values = (Set<Object>) value;
values.add(secondValue);
return values;
}
Set<Object> values = new HashSet<>();
values.add(value);
values.add(secondValue);
return values;
});
});
return map0;
}
}
以上代码打印:
{
"4100853125" : {
"localTimeStamp" : [ "20170523113305", "20190523113305" ],
"serviceCode" : [ "GPRS" ],
"recEntityCode" : [ [ "1", "2" ], [ "2", "4" ] ],
"index" : [ "1", "2" ],
"dataVolumeOutgoing" : [ "47600", "27600" ],
"callChargingId" : [ "4100853125" ],
"dataVolumeIncoming" : [ "400000", "300000" ]
},
"5100853125" : {
"localTimeStamp" : "20180523113305",
"serviceCode" : "GPRS",
"recEntityCode" : [ "1", "2" ],
"index" : "7",
"dataVolumeIncoming" : "100000",
"dataVolumeOutgoing" : "17600",
"callChargingId" : "5100853125"
}
}