'How to filter records in a nested array using ramda?
I've seen this question in several places but still can't figure this out.
Using ramda, how can I filter the following object to return the records that are true for tomatoes?
[
{
"id": "a",
"name": "fred",
"food_prefs": {
"tomatoes": true,
"spinach": true,
"pasta": false
},
"country": "singapore"
},
{
"id": "b",
"name": "alexandra",
"food_prefs": {
"tomatoes": false,
"spinach": true,
"pasta": true
},
"country": "france"
},
{
"id": "c",
"name": "george",
"food_prefs": {
"tomatoes": true,
"spinach": false,
"pasta": false
},
"country": "argentina"
}
]
Storing this array as myData object, I thought that the following should work:
const R = require("ramda")
const lovesTomatoes = R.pipe ( // taken from: https://stackoverflow.com/a/61480617/6105259
R.path (["food_prefs"]),
R.filter (R.prop ("tomatoes"))
)
console.log(lovesTomatoes(myData))
But I end up with the error:
if (typeof obj[methodNames[idx]] === 'function') {
What am I doing wrong?
EDIT
The answers provided by @Ori Drori and @ThanosDi are both great, but I want to emphasize that a pipe-based solution would be ideal because I have follow-up steps I wish to carry on the filtered array. Consider for example the following array. It's similar the one above, but includes more data: year_born and year_record.
[
{
"id": "a",
"name": "fred",
"year_born": 1995,
"year_record": 2010,
"food_prefs": {
"tomatoes": true,
"spinach": true,
"pasta": false
},
"country": "singapore"
},
{
"id": "b",
"name": "alexandra",
"year_born": 2002,
"year_record": 2015,
"food_prefs": {
"tomatoes": false,
"spinach": true,
"pasta": true
},
"country": "france"
},
{
"id": "c",
"name": "george",
"year_born": 1980,
"year_record": 2021,
"food_prefs": {
"tomatoes": true,
"spinach": false,
"pasta": false
},
"country": "argentina"
}
]
So, for example, to answer a full question such as "for those who love tomatoes, what is the average age at the time of the record creation?"
we would need to:
- filter the records that love tomates;
- extract the elements
year_bornandyear_record - get the difference between values
- take the average of the differences
Therefore, using a pipe would be very beneficial.
Solution 1:[1]
const myData = [
{
"id": "a",
"name": "fred",
"food_prefs": {
"tomatoes": true,
"spinach": true,
"pasta": false
},
"country": "singapore"
},
{
"id": "b",
"name": "alexandra",
"food_prefs": {
"tomatoes": false,
"spinach": true,
"pasta": true
},
"country": "france"
},
{
"id": "c",
"name": "george",
"food_prefs": {
"tomatoes": true,
"spinach": false,
"pasta": false
},
"country": "argentina"
}
];
const lovesTomatoes = filter(pathOr(false, ['food_prefs','tomatoes']));
lovesTomatoes(myData);
Ramda REPL
Solution 2:[2]
Ramda comes with a whole suite of predicates built-in already,
one of them that I'd use here is pathEq.
I'd suggest to adopt a map and reduce kind of approach, whereas the match function is separated from the actual aggregation...
- Collect your data point
- Reduce it to the information you need
const tomatoLovers = R.filter(
R.pathEq(['food_prefs', 'tomatoes'], true),
);
const avgAge = R.pipe(R.pluck('age'), R.mean);
const data = [{
"id": "a",
age: 16,
"name": "fred",
"food_prefs": {
"tomatoes": true,
"spinach": true,
"pasta": false
},
"country": "singapore"
},
{
"id": "b",
age: 66,
"name": "alexandra",
"food_prefs": {
"tomatoes": false,
"spinach": true,
"pasta": true
},
"country": "france"
},
{
"id": "c",
age: 44,
"name": "george",
"food_prefs": {
"tomatoes": true,
"spinach": false,
"pasta": false
},
"country": "argentina"
}
]
console.log(
'Average age of tomato lovers is:',
R.pipe(tomatoLovers, avgAge) (data),
);
console.log(
'They are the tomato lovers',
R.pipe(tomatoLovers, R.pluck('name')) (data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.js" integrity="sha512-ZZcBsXW4OcbCTfDlXbzGCamH1cANkg6EfZAN2ukOl7s5q8skbB+WndmAqFT8fuMzeuHkceqd5UbIDn7fcqJFgg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
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 | ThanosDi |
| Solution 2 |
