使用 Java 流获取 json 键的计数

Get Count of json key using Java Stream

我有一个 json 对象,看起来像这样

 [{
                "startAt": 1617605301292,
                "endAt": 1617605317095,
                "duration": 15803,
                "selection": {
                    "selected.Speed": "0",
                    "selected.Low": "65535",
                    "selected.Fast": "7173",
                    "selected.medium": "5"
                },
                "details": {
                    "phase": [{
                        "value": "2",
                        "timestamp": 1617605301316
                    }]
                }
            },
            {
                "startAt": 1617603849697,
                "endAt": 1617603966378,
                "duration": 116681,
                "selection": {
                    "selected.Speed": "0",
                    "selected.Low": "65535",
                    "selected.Fast": "123",
                    "selected.medium": "5"
                },
                "details": {
                    "phase": [{
                        "value": "2",
                        "timestamp": 1617603849749
                    }]
                }
            }
        ]

我需要计算 selected.Fast 发生了多少次。我正在尝试使用流,这是我到目前为止所写的

List<Map<String, Object>> jsonObj = mapper.readValue(jArr, new TypeReference<List<Map<String, Object>>>(){});
                
Map<String, Long> counted = jsonObj.stream()
        .map(x -> x.get("selection").toString() )
        .collect(Collectors.toList())
        .stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

System.out.println(counted.toString());

            

但是我正在计算选择对象中的所有键,我想计算特定的 Json 键,即 selected.Fast 例如 selected.Fast:"7173" -> occurred - 5times selected.Fast:"123" -> occurred - 2times

如有任何帮助,我们将不胜感激。

I need to count how many times selected.Fast has occurred.

这是你想要的吗?

List<Map<String, Object>> jsonObj = mapper.readValue(jArr, new TypeReference<List<Map<String, Object>>>(){});
                
long count = jsonObj.stream()
        .map(x -> x.get("selection").toString())
        .filter(s -> s.contains("selected.Fast"))
        .count()

System.out.println(count);

您可以使用 jackson 库正常反序列化并创建这样的对象结构:

    @Setter
    @Getter
    @NoArgsConstructor
    static class Source {

        private long startAt;

        private long endAt;

        private long duration;

        private SourceSelection selection;

        private SourceDetails details;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    static class SourceSelection {

        private long speed;

        private long low;

        private long fast;

        private long medium;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    static class SourceDetails {

        private List<SourcePhase> phase;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    static class SourcePhase {

        private int value;

        private long timestamp;
    }

然后您需要将 json 反序列化为 Source.class 对象:

List<Source> sourceList = new ObjectMapper().readValue(
        JSON,
        new ObjectMapper().getTypeFactory().constructCollectionType(List.class, Source.class)
);

JSON 是您的来源时 json

然后您可以使用标准流 API 进行映射、过滤和计数:

    long result = sourceList.stream()
            .map(Source::getSelection)
            .filter(s-> s.getFast() != 0)
            .count();

你能看看这是否是你要找的吗?

 List<JsonNode> jsonObj = mapper.readValue(jArr, new TypeReference<List<JsonNode>>() {
    });

    Map<String, Long> counted = jsonObj.stream()
            .map(x -> {
                String selection = x.get("selection").get("selected.Fast").asText();
                return "selected.Fast:" + selection;
            }).collect(Collectors.toList())
            .stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    System.out.println(counted); //{selected.Fast:123=1, selected.Fast:7173=1}

编辑:不转换为 JsonNode

    List<Map<String, Object>> jsonObj = mapper.readValue(jArr, new TypeReference<List<Map<String, Object>>>(){});

    Map<String, Long> counted = jsonObj.stream()
            .map(x -> {
                String selection = ((Map<String,Object>)x.get("selection")).get("selected.Fast").toString();
                return "selected.Fast:" + selection;
            }).collect(Collectors.toList())
            .stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    System.out.println(counted);

编辑 2:计算所选内容中所有元素的数量的解决方案

    Map<String, Long> counted = jsonObj.stream().flatMap(x -> {
        JsonNode selection = x.get("selection");
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(selection.fields(), 0), false);
    })
            .map(x -> x.getKey() + ":" + x.getValue()).collect(Collectors.toList())
            .stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    System.out.println(counted);

要输出层数不定的JSON记录的所有层级中指定名称的字段信息,Java代码会很长很复杂

您可以使用 open-source Java 软件包 SPL 来执行此操作。很简单,一行代码就够了:

A
1 =json(file("data.json").read()).groups(#4.#3;count(~)).("selected.Fast:\""/#1/""-> occurred -"/#2/"times")

SPL 提供 JDBC 驱动程序供 Java 调用。只需将上面的 SPL 脚本存储为 count.splx 并在调用存储过程时在 Java 中调用它:

…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call count()");
st.execute();
…