I'm really struggling trying to do this, so I apologize (jq isn't my forte).
I have a file with a json array like this one:
[
{
"name": "aaaaa",
"description": "aaaaa",
"attributes": [
{
"trait": "Color 1",
"value": "Blue"
},
{
"trait": "Color 2",
"value": "Yellow"
},
{
"trait": "Hair",
"value": "Wild"
}
]
},
{
"name": "bbbbb",
"description": "bbbbbb",
"attributes": [
{
"trait": "Color 1",
"value": "Blue"
},
{
"trait": "Color 2",
"value": "Red"
},
{
"trait": "Hair",
"value": "Wild"
}
]
}
]
I'd like to output a json object that shows the count of each trait so the end result would include something like
{
"Color 1": {
"Blue":2
},
"Color 2":{
"Yellow":1,
"Red":1
},
"Hair":{
"Wild":2
}
}
This is probably not too difficult but like I said, I suck at jq :)
CodePudding user response:
Having in mind the concepts of group by
and bag-of-words
as defined by:
def bow(stream):
reduce stream as $word ({}; .[($word|tostring)] = 1);
it's not hard to see that the following produces the result shown immediately below:
map(.attributes[])
| group_by(.trait)
| map( { (.[0].trait): bow(.[].value) } )
[{"Color 1":{"Blue":2}},{"Color 2":{"Yellow":1,"Red":1}},{"Hair":{"Wild":2}}]
So to get the result you want, simply add | add
to the pipeline.
CodePudding user response:
const traits = input.reduce((aggr, obj) => aggr.concat(obj.attributes), []);
const traitSet = traits.reduce((aggr, {trait, value}) => {
if(!aggr[trait]) {
aggr[trait] = {};
}
if(!aggr[trait][value]){
aggr[trait][value] = 0;
}
aggr[trait][value] = aggr[trait][value] 1
return aggr;
}, {});
console.log(traitSet);
// or console.log(JSON.stringify(traitSet)) - since you asked for JSON
Just a very quick version and vanilla version. This code can be made chained or less verbose by using libraries like lodash.