[英]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
?使用
ramda
,如何过滤以下 object 以返回tomatoes
的true
记录?
[
{
"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:将此数组存储为
myData
object,我认为以下应该有效:
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') {
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. @Ori Drori 和 @ThanosDi 提供的答案都很棒,但我想强调的是,基于pipe的解决方案将是理想的,因为我有后续步骤我希望继续过滤数组。 Consider for example the following array.
例如,考虑以下数组。 It's similar the one above, but includes more data:
year_born
and year_record
.它与上述类似,但包含更多数据:
year_born
和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:我们需要:
year_born
and year_record
year_born
和year_record
Therefore, using a pipe would be very beneficial.因此,使用 pipe 将非常有益。
What went wrong?什么地方出了错?
You try to get the value of food_prefs
out of the array.您尝试从数组中获取
food_prefs
的值。 Since the array doesn't have this key - R.path (["food_prefs"])
is undefined
, and then you try to filter this undefined
value.由于数组没有这个键 -
R.path (["food_prefs"])
is undefined
,然后你尝试过滤这个undefined
的值。
How to solve this problem?如何解决这个问题呢?
Filter the array, and use R. pathSatisfies
过滤数组,并使用
R. pathSatisfies
R. pathSatisfies
for each object to check if a nested property conforms to a criteria. R. pathSatisfies
为每个 object 检查嵌套属性是否符合标准。 Since the value in this case is a boolean, you can use R.identity
as the predicate.由于本例中的值为 boolean,因此您可以使用
R.identity
作为谓词。
const { filter, pathSatisfies, identity } = R const lovesTomatoes = filter(pathSatisfies(identity, ['food_prefs', 'tomatoes'])) const data = [{"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 result = lovesTomatoes(data) console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Filtering using a pipe:使用 pipe 过滤:
Using R.pipe
.使用
R.pipe
。 I wouldn't go this way for a simple filter by nested properties, but you can use a Schwartzian transform .对于嵌套属性的简单过滤器,我不会 go 这种方式,但您可以使用Schwartzian transform 。 The idea is to create a new array if pairs
[value of tomato, original object]
, filter by the value of tomato, and then extract the original object:这个想法是创建一个新数组 if 对
[value of tomato, original object]
,通过番茄的值进行过滤,然后提取原始 object:
const { pipe, map, applySpec, path, identity, filter, last, head } = R const lovesTomatoes = pipe( map(applySpec([path(['food_prefs', 'tomatoes']), identity])), // create an array of [value of tomatoes, original object] filter(head), // filter by the value of the tomatoes map(last) // extract the original object ) const data = [{"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 result = lovesTomatoes(data) console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
How to combine the 1st lovesTomatoes
filtering function in a pipe:如何在 pipe 中组合第一个
lovesTomatoes
过滤function:
However, if you just need the pipe to perform other operations on the filtered array, use the filter as one of the steps:但是,如果您只需要 pipe 对过滤后的数组执行其他操作,请使用过滤器作为步骤之一:
const { filter, pathSatisfies, identity, pipe, map, prop, uniq } = R const lovesTomatoes = filter(pathSatisfies(identity, ['food_prefs', 'tomatoes'])) const countriesOfTomatoLovers = pipe( lovesTomatoes, map(prop('country')), uniq ) const data = [{"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 result = countriesOfTomatoLovers(data) console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
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 comes with a whole suite of predicates built-in already, one of them that I'd use here is pathEq
. Ramda 已经内置了一整套谓词,我在这里使用的其中一个谓词是
pathEq
。
I'd suggest to adopt a map
and reduce
kind of approach, whereas the match function is separated from the actual aggregation...我建议采用
map
并reduce
这种方法,而匹配 function 与实际聚合分开......
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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.