过滤具有相同 ID 和给定条件的对象的 json 数组
Posted
技术标签:
【中文标题】过滤具有相同 ID 和给定条件的对象的 json 数组【英文标题】:filter a json array of objects with same ID and given condition 【发布时间】:2022-01-18 08:56:25 【问题描述】:给定一个像这样的 Json 数组:
["TID":"12P","APP":"V", "TID":"12P","APP":"S",
"TID":"12P","APP":"V_xz", "TID":"12P","APP":"V_tvc",
"TID":"78L","APP":"V", "TID":"78L","APP":"V_tvc",
"TID":"7MP","APP":"S", "TID":"7MP","APP":"V_tvc",
"TID":"5P","APP":"V_xv", "TID":"5P","APP":"V_cd"]
上述Json Array的最终输出应该是:
["TID":"12P","APP":"V",
"TID":"78L","APP":"V",
"TID":"7MP","APP":"S"]
对于每条具有相同 TID 的记录,我必须检查对象是否:
-
让 APP 同时存在“V”和“S”,然后只获取 APP="V" 的对象
将 APP 设为“V”而不是“S”,则应获取 APP="V" 的对象
将 APP 设为“S”而不是“V”,则应获取 APP="S" 的对象
应忽略 APP 作为“V”和“S”以外的值
【问题讨论】:
请分享您解决此问题的尝试...练习? 【参考方案1】:解决方案可能会因使用的JsonArray
实现而异,但一般方法包括以下任务:
-
将输入的JSON字符串读入
JsonArray
迭代输入数组,过滤掉包含"APP"
字段且值不是"V"
或"S"
的值
按"TID"
字段分组,解决冲突以支持"V"
值
添加到结果JsonArray
如果使用javax.json.JsonArray
,解决方案代码如下:
static JsonArray filterArray(String json)
JsonReader reader = Json.createReader(new StringReader(json));
JsonArray jsonaArray = reader.readArray();
Set<String> appValues = new HashSet<>(Arrays.asList("V", "S"));
return jsonaArray.stream()
.map(JsonObject.class::cast)
.filter(jo -> appValues.contains(jo.getString("APP")))
.collect(Collectors.toMap(
jo -> jo.getString("TID"),
jo -> jo,
(v1, v2) -> Stream.of(v1, v2)
.sorted(Comparator.comparing((JsonObject job) -> job.getString("APP"))
.reversed()
)
.findFirst().get(),
LinkedHashMap::new
))
.values()
.stream()
.collect(JsonCollectors.toJsonArray());
这里使用javax.json-api
库提供JsonCollectors
测试:
String JSON = ...; // long JSON data
System.out.println(filterArray(JSON));
输出:
["TID":"12P","APP":"V","TID":"78L","APP":"V","TID":"7MP","APP":"S"]
使用 Jackson 库的类似解决方案:
static ArrayNode filterArrayJackson(String json) throws IOException
Set<String> appValues = new HashSet<>(Arrays.asList("V", "S"));
ObjectMapper mapper = new ObjectMapper();
ArrayNode array = (ArrayNode) mapper.readTree(new StringReader(json));
return StreamSupport.stream(array.spliterator(), false)
.filter(node -> appValues.contains(node.get("APP").asText()))
.collect(Collectors.toMap(
node -> node.get("TID").asText(),
node -> node,
(v1, v2) -> Stream.of(v1, v2)
.sorted(Comparator.comparing((JsonNode job) -> job.get("APP").asText())
.reversed()
)
.findFirst().get(),
LinkedHashMap::new
))
.values()
.stream()
.reduce(
mapper.createArrayNode(),
ArrayNode::add,
(acc, arr) -> acc.addAll(arr); return acc;
);
可以使用自定义收集器代替Stream::reduce
:
// ...
.collect(Collector.of(
mapper::createArrayNode, ArrayNode::add,
(acc, arr) -> acc.addAll(arr); return acc;
));
【讨论】:
以上是关于过滤具有相同 ID 和给定条件的对象的 json 数组的主要内容,如果未能解决你的问题,请参考以下文章
无法使用杰克逊反序列化包含 2 个具有相同 ID 的对象的 Json