[英]How to filter records in a nested array using ramda?
我已经在几个地方看到了这个问题,但仍然无法弄清楚。 使用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"
}
]
将此数组存储为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))
但我最终得到了错误:
if (typeof obj[methodNames[idx]] === 'function') {
我究竟做错了什么?
编辑
@Ori Drori 和 @ThanosDi 提供的答案都很棒,但我想强调的是,基于pipe的解决方案将是理想的,因为我有后续步骤我希望继续过滤数组。 例如,考虑以下数组。 它与上述类似,但包含更多数据: 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"
}
]
因此,例如,要回答一个完整的问题,例如“对于喜欢西红柿的人来说,创造纪录时的平均年龄是多少?”
我们需要:
year_born
和year_record
因此,使用 pipe 将非常有益。
什么地方出了错?
您尝试从数组中获取food_prefs
的值。 由于数组没有这个键 - R.path (["food_prefs"])
is undefined
,然后你尝试过滤这个undefined
的值。
如何解决这个问题呢?
过滤数组,并使用R. pathSatisfies
R. pathSatisfies
为每个 object 检查嵌套属性是否符合标准。 由于本例中的值为 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>
使用 pipe 过滤:
使用R.pipe
。 对于嵌套属性的简单过滤器,我不会 go 这种方式,但您可以使用Schwartzian transform 。 这个想法是创建一个新数组 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>
如何在 pipe 中组合第一个lovesTomatoes
过滤function:
但是,如果您只需要 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);
拉姆达REPL
Ramda 已经内置了一整套谓词,我在这里使用的其中一个谓词是pathEq
。
我建议采用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.