i have request :
"questionType": "questionType",
"question": [
{
"questionId": "questionIdFirst",
"answer": [
{
"input": "input1",
"answerOption": [
{
"answerId": "AnswerId1",
"score": 7
}
]
},
{
"input": "input2",
"answerOption": [
{
"answerId": "AnswerId2",
"score": 8
}
]
}
]
},
{
"questionId": "questionIdSecond",
"answer": [
{
"input": "input3",
"answerOption": [
{
"answerId": "answerId",
"score": 9
}
]
},
{
"input": "input4",
"answerOption": [
{
"answerId": "answerId",
"score": 10
}
]
}
]
}
]
}
and i want to get maxValues score in object answerOption with stream filter or foreach, how can i do this?
i try to this and cannot resolve :
input.getQuestionnaire().getQuestion().stream()
.forEach(quest -> quest.getAnswer().stream()
.forEach(answer -> answer.getAnswerOption()
.stream().max(Comparator.comparing(AnswerOption::getScore))));
and then, in i want to get maxValues, i select to DB and then i want to replace answerOption for request sample to database
For retrieving the max score AnswerOption in your Questionnaire try the following (you need flatMap to flatten the inner lists and get the max comparator result as output)
final Optional<AnswerOption> max = input.getQuestionnaire().getQuestion().stream().map(Question::getAnswer)
.flatMap(Collection::stream)
.map(Answer::getAnswerOption).flatMap(Collection::stream)
.max(Comparator.comparing(AnswerOption::getScore));
Related
I have two lists of same type:
Boxes1 and Boxes2:
"boxes1": [{
"boxId": "ABC",
"ele": [{
"eleId": "8040",
"chars": [{
"no": "123",
"qty": 2
}
]
}
]
}, {
"boxId": "XYZ",
"ele": [{
"eleId": "1212",
"chars": [{
"no": "456",
"qty": 3
}
]
}
]
}
]
And
"boxes2": [{
"boxId": "ABC",
"ele": [{
"eleId": "8040",
"chars": [{
"no": "123",
"qty": 6
}
]
}, {
"eleId": "4560",
"chars": [{
"no": "012",
"qty": 3
}
]
}
]
}, {
"boxId": "PQR",
"ele": [{
"eleId": "1111",
"chars": [{
"no": "456",
"qty": 8
}
]
}
]
}
]
I want check if any boxId from boxes1 matches with a boxId from boxes2, then I want to add the chars of the a common element eleId of box1 into box2 so that the result looks like this after combining:
"box2": [{
"boxId": "ABC",
"ele": [{
"eleId": "8040",
"chars": [{
"no": "123",
"qty": 6
},
{
"no": "123",
"qty": 2
}
]
},.....................
and also if there is any boxId from Boxes1 that is not present in Boxes2 I want to add that box inside the Boxes2. so finally it should look like :
"box2": [{
"boxId": "ABC",
"ele": [{
"eleId": "8040",
"chars": [{
"no": "123",
"qty": 6
}, {
"no": "123",
"qty": 2
}
]
}, {
"eleId": "4560",
"chars": [{
"no": "012",
"qty": 3
}
]
}
]
}, {
"boxId": "PQR",
"ele": [{
"eleId": "1111",
"chars": [{
"no": "456",
"qty": 8
}
]
}
]
}, {
"boxId": "XYZ",
"ele": [{
"eleId": "1212",
"chars": [{
"no": "456",
"qty": 3
}
]
}
]
}
]
I am new to Stream so tried using the old way but it has issue:
boxes2.forEach(box2 -> {
boxes1.forEach(box1 -> {
if (box1.getBoxId().equals(box2.getBoxId())) {
box2.getEle().forEach(ele1 -> {
box1.getEle().forEach(ele2 -> {
if (ele1.getEleId().equals(ele2.getEleId())) {
ele1.chars().addAll(ele2.chars());
}
});
});
} else {
boxes2.add(box1);
}
});
});
Using Streams won't help much in your case. I'd suggest to go for POIC (plain old imperative code).
Pseudo code alorithm:
for ( box1 of boxes1 ) {
var box1Id = box.boxId;
if ( boxes2.containsBoxId(box1Id) ) {
var box2 = boxes2.getBoxById(boxId);
for ( ele1 of box1.ele ) {
var ele1Id = ele1.eleId;
if ( box2.containsEleId(ele1Id) ) {
var ele2 = box2.getEleById(ele1Id);
ele2.addToChars(ele1.chars);
}
}
} else {
// if boxes2 doesn't contain box1Id
boxes2.addBox(box1);
}
}
The only thing I would consider for Streams is the "find matching ele and add chars" part. But that will get slow for huge collections.
var box1Id = ...
var box1ele = ...
boxes2.stream()
.filter(b -> b.boxId.equals(box1Id))
.flatMap(b -> b.ele.stream())
.filter(e -> e.eleId.equals(box1ele))
.forEach(e -> e.addChars(box1ele.chars)
You could of course do the box1 iteration with Streams, too. But that will lead to some really ugly and unreadable code. (EDIT: Just like your example code: Not nice.)
What you could do instead: Put the relevant data in a Map for faster and easier access without all those loops.
An other solution is like this:
List<Box> boxResult = Stream.concat(boxes1.stream(), boxes2.stream())
.collect(toMap(Box::getBoxId,
v-> new ArrayList<>(v.getEle()),
YOUR_CLASS::mergeEle))
.entrySet().stream()
.map(entry -> new Box(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
and mergeEle method:
private static List<Ele> mergeEle(List<Ele> l1, List<Ele> l2) {
return Stream.concat(l1.stream(), l2.stream())
.collect(toMap(Ele::getEleId,
v -> new ArrayList<>(v.getChars()),
YOUR_CLASS::mergeChar))
.entrySet().stream()
.map(e -> new Ele(e.getKey(), e.getValue()))
.collect(Collectors.toList());
}
and mergeChar:
private List<Char> mergeChar(List<Char> c1, List<Char> c2) {
c1.addAll(c2);
return c1;
}
Consider the code snippet below-
{
"header": {
"systemId": "1"
},
"body": {
"approvalType": "S",
"requester": "CRM",
"approver": "V",
"additionalInfoList": [
{
"additionalInfoItem": {
"value": [
{
"secret": [
{
"question": "1"
}
]
},
{
"secret": [
{
"question": "2"
}
]
},
{
"secret": [
{
"question": "3"
}
]
}
]
}
},
{
"additionalInfoItem": {
"name": "key2",
"value": [
{
"secret": [
{
"question": "00"
}
]
},
{
"secret": [
{
"question": "002"
}
]
},
{
"secret": [
{
"question": "003"
}
]
}
]
}
}
]
}
}
For this json path
$.body.additionalInfoList[*].additionalInfoItem.value[*].secret[*].question
the API gives
[
"1",
"2",
"3",
"00",
"002",
"003"
]
I am using configuration REQUIRE_PROPERTIES option which configures JsonPath to require properties defined in path when an indefinite path is evaluated.
If in the above JSON, one of the question is not sent in request, an exception as below will be thrown - No results for path: $['body']['additionalInfoList'][1]['additionalInfoItem']['value'][0]['secret'][0]['question']
I have a requirement to collect all other values for the question tag even when the exception com.jayway.jsonpath.PathNotFoundException was thrown. How can I achieve this?
On the other hand, if I use the option SUPPRESS_EXCEPTIONS, how can I know if there is a missing path?
I do not have a great answer here; however, to get it done I would suggest processing the response twice:
once with SUPPRESS_EXCEPTIONS (or simply no option might work as well),
and then with REQUIRE_PROPERTIES to detect the errors.
This should allow you to handle the scenario as described.
I am trying to do JOLT shift operation with below spec which is not working. Not sure what mistake I have done. Need help in this case. Output JSON is coming as an object instead of Array and shift also not working as expected.
Input : [
{
"Header": {
"Number": 1,
"Id": "JO"
},
"Name": "John"
},
{
"Header": {
"Number": 2,
"Id": "JS"
},
"Name": "Justin"
}
]
Spec : [
{
"operation": "shift",
"spec": {
"*": {
"Header": "Header",
"Name": "Header.Name"
}
}
}
]
Expected Output : [
{
"Header": {
"Number": 1,
"Id": "JO",
"Name": "John"
}
},
{
"Header": {
"Number": 2,
"Id": "JS",
"Name": "Justin"
}
}
]
Actual Output : {
"Header" : [ {
"Number" : 1,
"Id" : "JO",
"Name" : "John"
}, {
"Number" : 2,
"Id" : "JS"
} ]
}
You have to also specify that the "Header" object is inside the array.
Moreover, the index of the array where you place the "Header" object for each of the element of the array.
That's what the spec below does (using the [&1] - apmersand wildcard combined with array):
[
{
"operation": "shift",
"spec": {
"*": {
"Header": "[&1].Header",
"Name": "[&1].Header.Name"
}
}
}
]
Sources:
Shiftr.java javadocs:
The arrays
The ampersand wildcard
Other answer: "How do I transform an array using Jolt?"
Demo application linked in the jolt repo to test the spec
We have a response JSON that comes in below format. There is a need for us to process this json efficiently and log some of the the item Ids that are missing some important information such as options block(at least for debugging purpose). Included the sample response below.
{
"items": [
{
"itemId": "xxx",
"priceList": [
{
"price": 0.0,
"options": [
{
"price": 0.0,
"priceType": "yyy"
}
]
}
]
},
{
"itemId": "xxx",
"priceList": [
{
"price": 0.0
}
]
},
{
"itemId": "xxx",
"priceList": [
{
"price": 0.0,
"options": [
{
"price": 0.0,
"priceType": "yyy"
}
]
}
]
},
{
"itemId": "xxx",
"priceList": [
{
"price": 0.0
}
]
}
]
}
I am able to log the missing item ids as below
items.forEach(item -> {
if (CollectionUtils.isEmpty(item.getUoms().get(0).getPricingOptions())) {
log.info("price options is missing for item {} ", item.getItemId());
}
});
Is there better/faster way to do this?
Thanks
Not sure if you'd call this better, but you can use streams to implement this:
items.stream()
.filter(it -> it.getUoms().get(0).getPricingOptions().isEmpty())
.forEach(it -> log.info("price options is missing for item {} ", it.getItemId()));
I want to make my code as simple as I can and don't want to download items which are not needed.
I want to select only Pages when I'm admin on facebook.
For now I use:
https://graph.facebook.com/v2.0/me/?fields=id,accounts{id,perms}&summary=true&limit=100&access_token=MY_TOKEN
Results:
{
"id": "101506",
"accounts": {
"data": [
{
"id": "6986842335",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
{
"id": "1374577066121",
"perms": [
"BASIC_ADMIN"
]
},
{
"id": "997587036984",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
],
}
}
Now, how to change the query to read only items with perms=ADMINISTER ?
This is what I need:
{
"id": "101506",
"accounts": {
"data": [
{
"id": "6986842335",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
{
"id": "997587036984",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
],
}
}
If I can't make the query to read what I need, maybe you know how to do this in Java to check the length of pages?
For now I have:
User = facebookClient.fetchObject("v2.0/me", JsonObject.class, Parameter.with("summary", true), Parameter.with("fields", "id,name,accounts{id,perms}"), Parameter.with("limit", 100));
Integer userFPCount = User.getJsonObject("accounts").getJsonArray("data").length();
But this code gives me results: 3. How to check the length of accounts.data.perms(ADMINISTER) ? I should have result: 2 in this example.
THANK YOU FOR YOUR HELP !