Json 使用java流对复杂对象进行分组列表
我有一个gprsEvents列表,其中列表中的每个元素都是一个映射,如下所示。我需要:Json 使用java流对复杂对象进行分组列表,json,java-8,stream,grouping,collectors,Json,Java 8,Stream,Grouping,Collectors,我有一个gprsEvents列表,其中列表中的每个元素都是一个映射,如下所示。我需要: { "events":[ { "localTimeStamp":"20170523113305", "serviceCode":"GPRS", "recEntityCode":[ "1&
{
"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",
}
]
}
我现在一直想得到合适的结果,特别是在一个单独的映射和上述字段的列表或总和中得到结果…这里的关键点是实现
BinaryOperator mergeFunction
对象,它将完成最复杂的部分:合并两个Map
实例。我建议使用一个带有3个参数的方法:
keyMapper
-callChargingId
valuevalueMapper
-Map
实例mergeFunction
-将合并类型为BinaryOperator
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;
}
}
没有必要在每次合并时都创建一个新映射。只要在值映射器中创建映射的副本,添加到左侧映射就足够了。另外,为什么不使用方法引用而不是新类?@fps:1。
新映射
-很好。我只是想显式地显示它将是一个合并
点,但我在这里看到了it’没有理由创建一个新实例。也许与parallelStream
一起使用会更安全些?你怎么看?2.为什么不使用方法引用
-只是为了清楚地显示我在答案顶部提到的3个参数。当然,最终的解决方案取决于作者,可以作为方法引用轻松地移到内部nce。当我们创建这样的类时,提供单元测试也要容易得多。parallelStream
在大多数情况下使用较慢或不正确,但与安全无关。您可以选择并行或不并行。至于使用方法引用,您完全正确,这是个人喜好的问题
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"
}
}