Cool tool, struggling to start using this. might be faster asking this simple question here:
I have this:
[
{
"title": "Singapore",
"value": 5
},
{
"title": "China",
"value": 2
},
{
"title": "Singapore",
"value": 7
}
]
I want this:
[
{
"title": "Singapore",
"value": 12
},
{
"title": "China",
"value": 2
}
]
how to reduce this?
group_by(.title) | map({"title": .[0].title, value: map(.value) | add})
This groups the elements of the array by title, and then, for each group, generates an object with the title of the elements of the group and the sum of the values of the elements of the group.
worked like a charm :)
Here's a slightly different approach that uses "reduce" explicitly. It takes advantage of the fact that your titles are all strings, and for this reason, is more efficient in that it does not require a "sort" (as performed by "group_by").
In brief, we create a single object with (title, total-value) pairs, and then convert it to the desired form.
The function for converting an object such as {"Singapore": 12,"China": 2} to an array of title-value objects is as follows:
def objects(key; value): . as $in | reduce keys[] as $key ([]; . + [{ (key): $key, (value): $in[$key] }]);
To accomplish the task, we can now simply write:
reduce .[] as $x ({}; . + { ($x.title): ($x.value + (.[$x.title] )) })
| objects("title"; "value")
Here's another way:
group_by(.title)|.[] | reduce .[] as $item (null; .title = $item.title | .value |= . + $item.value)
This one reduces each group, keeping the title from each item in the group (it must always be the same, since we grouped by title) and adding the values. This depends on addition of null to a number being the same as addition of zero to a number, though we can drop that dependency too:
group_by(.title)|.[] | reduce .[] as $item ({}; .title = $item.title | .value |= (.//0) + $item.value)
We could make a nice little function out of this:
def group_reduce(group_by_exp; reduction_exp):
group_by(group_by_exp) | .[] | reduce .[] as $item ({}; (group_by_exp) = ($item | group_by_exp) | [., $item] | reduction_exp);
group_reduce(.title; (.[1] as $right|.[0]|.value |= (. + $right.value)))
Most helpful comment
group_by(.title) | map({"title": .[0].title, value: map(.value) | add})This groups the elements of the array by title, and then, for each group, generates an object with the title of the elements of the group and the sum of the values of the elements of the group.