繁体   English   中英

如何使用 ramda 过滤嵌套数组中的记录?

[英]How to filter records in a nested array using ramda?

我已经在几个地方看到了这个问题,但仍然无法弄清楚。 使用ramda ,如何过滤以下 object 以返回tomatoestrue记录?

[
    {
        "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_bornyear_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"
    }
]

因此,例如,要回答一个完整的问题,例如“对于喜欢西红柿的人来说,创造纪录时的平均年龄是多少?”

我们需要:

  1. 过滤喜欢番茄的记录;
  2. 提取元素year_bornyear_record
  3. 获取值之间的差异
  4. 取差异的平均值

因此,使用 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

我建议采用mapreduce这种方法,而匹配 function 与实际聚合分开......

  1. 收集您的数据点
  2. 将其简化为您需要的信息

 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM