'Get Count of json key using Java Stream
I have a json object that looks like this
[{
"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
}]
}
}
]
I need to count how many times selected.Fast has occurred. I am trying with stream and this is what I have written so far
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());
But I am getting count of all the key inside selection object, and I want count for specific Json key which is selected.Fast
For Example
selected.Fast:"7173" -> occurred - 5times selected.Fast:"123" -> occurred - 2times
Any help would be appreciated.
Solution 1:[1]
Can you check if this is what you are looking for ?
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}
Edit: Without converting to 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);
Edit 2: Solution to get count of all the elements inside the selection
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);
Solution 2:[2]
I need to count how many times selected.Fast has occurred.
Is this what you're after?
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);
Solution 3:[3]
You can use normally deserialize by jackson library and create object structure like that:
@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;
}
And then you need to deserialize your json to Source.class object:
List<Source> sourceList = new ObjectMapper().readValue(
JSON,
new ObjectMapper().getTypeFactory().constructCollectionType(List.class, Source.class)
);
When JSON
is your source json
And then you can use a standart stream API for mapping, filtering, and counting:
long result = sourceList.stream()
.map(Source::getSelection)
.filter(s-> s.getFast() != 0)
.count();
Solution 4:[4]
To output information about a field of the specified name in all levels of JSON records that have indefinite number of levels, the Java code will be long and complicated.
You can use SPL, the open-source Java package, to do this. It is easy and only one line of code is enough:
A | |
---|---|
1 | =json(file("data.json").read()).groups(#4.#3;count(~)).("selected.Fast:\""/#1/""-> occurred -"/#2/"times") |
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as count.splx and invoke it in Java as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call count()");
st.execute();
…
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | jon-hanson |
Solution 3 | Dmitrii B |
Solution 4 | LeoTaylor |