【问题标题】:filter a json array of objects with same ID and given condition过滤具有相同 ID 和给定条件的对象的 json 数组
【发布时间】: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 的记录,我必须检查对象是否:

  1. 让 APP 同时存在“V”和“S”,然后只获取 APP="V" 的对象
  2. 将 APP 设为“V”而不是“S”,则应获取 APP="V" 的对象
  3. 将 APP 设为“S”而不是“V”,则应获取 APP="S" 的对象
  4. 应忽略 APP 作为“V”和“S”以外的值

【问题讨论】:

  • 请分享您解决此问题的尝试...练习?

标签: java arrays json


【解决方案1】:

解决方案可能会因使用的JsonArray 实现而异,但一般方法包括以下任务:

  1. 将输入的JSON字符串读入JsonArray
  2. 迭代输入数组,过滤掉包含"APP"字段且值不是"V""S"的值
  3. "TID" 字段分组,解决冲突以支持"V"
  4. 添加到结果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;}
    ));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-05
    • 2020-08-13
    • 2019-10-03
    • 2011-08-31
    • 1970-01-01
    • 2019-10-03
    相关资源
    最近更新 更多