gpt4 book ai didi

javascript - 访问 compose 函数 Ramda 内的数据

转载 作者:行者123 更新时间:2023-11-28 13:08:39 24 4
gpt4 key购买 nike

我正在使用 Ramda 来为某些数据提供结构。但是,我无法访问 compose 内的数据。

  1. 它应该映射 level 大于 2 的项目,但这不起作用

[键, compose(map(map(find(propEq('level',> 2)))),values)]

  • 我试图将 typeChild 中的所有项目保持为唯一
  • 这是用于测试它的 ramda 控制台(必须点击那里的链接,所以不允许 goo.gl 链接):http://dpaste.com/0SATTZK

    const result = pipe(
    pluck('type'),
    groupBy(
    pipe(
    find(propEq('level', 1)),
    propOr('NoLevel', 'name'),
    )
    ),
    converge(
    zipWith(unapply(zipObj(['name', 'typeChild']))),
    [keys, compose(map(map(find(propEq('level', 2)))), values)]
    ),
    );
    result(data)

    输入数据

    [{
    "title": "Apple",
    "type": [{"name": "Food", "level": 1}, {"name": "Fruit", "level": 2}]
    }, {
    "title": "Tomato",
    "type": [{"name": "Food", "level": 1}, {"name": "Fruit", "level": 2}]
    }, {
    "title": "Potato",
    "type": [{"name": "Food", "level": 1}, {"name": "Vegetable", "level": 2}]
    }, {
    "title": "The Alchemist",
    "type": [{"name": "Entertainment", "level": 1}, { "name": "Book", "level": 2}]
    }, {
    "title": "Superman",
    "type": [{"name": "Entertainment", "level": 1}, {"name": "Movie", "level": 2}]
    }, {
    "title": "More facts",
    "type": [{"name": "Foo", "level": 2}]
    }, {
    "title": "Superman",
    "type": [{"name": "Bar", "level": 1}]
    }
    ];

    期望的输出

    [

    {name: "Food", typechild: [{level: 2, name: "Fruit"}, {level: 2, name: "Vegetable"}]},
    {name: "Entertainment", typechild: [{level: 2, name: "Book"}, {level: 2, name: "Movie"}]},
    {name: "NoName", typechild: [{level: 2, name: "Foo"}]},
    {name: "Bar", typechild: []}
    ]

    最佳答案

    好的,我将猜测您要查找的内容。

    <小时/>

    显示数据

    首先,您确实需要演示输入数据的某些部分。我把它简化为:

    const data =[{
    "title": "Apple",
    "type": [{"name": "Food", "level": 1}, {"name": "Fruit", "level": 2}]
    }, {
    "title": "Tomato",
    "type": [{"name": "Food", "level": 1}, {"name": "Fruit", "level": 2}]
    }, {
    "title": "Potato",
    "type": [{"name": "Food", "level": 1}, {"name": "Vegetable", "level": 2}]
    }, {
    "title": "The Alchemist",
    "type": [{"name": "Entertainment", "level": 1}, { "name": "Book", "level": 2}]
    }, {
    "title": "Superman",
    "type": [{"name": "Entertainment", "level": 1}, {"name": "Movie", "level": 2}]
    }, {
    "title": "More facts",
    "type": [{"name": "Foo", "level": 2}]
    }, {
    "title": "Superman",
    "type": [{"name": "Bar", "level": 1}]
    }
    ];

    (请注意,我从每种类型中删除了 color 属性,因为它们似乎与讨论无关,但它们不会改变任何内容。)

    从你的尝试中我猜测需要输出类似这样的内容:

    [
    {name: "Food", typechild: [{level: 2, name: "Fruit"}, {level: 2, name: "Vegetable"}]},
    {name: "Entertainment", typechild: [{level: 2, name: "Book"}, {level: 2, name: "Movie"}]},
    {name: "NoName", typechild: [{level: 2, name: "Foo"}]},
    {name: "Bar", typechild: []}
    ]

    通过组合函数来解决这个问题

    这是一种方法:

    const levelEq = (n) => pipe(prop('level'), equals(n));
    const topLevel = pipe(prop('type'), find(levelEq(1)));
    const topLevelName = pipe(topLevel, propOr('NoName', 'name'));
    const extract2ndLevel = pipe(pluck('type'), flatten, filter(levelEq(2)));

    const convert = pipe(
    groupBy(topLevelName),
    map(extract2ndLevel),
    map(uniq),
    toPairs,
    map(zipObj(['name', 'typechild']))
    );

    convert(data); //=> (the first output format above)

    (通常对于那些单行代码,我会使用 pipe ,而不是 compose ,并颠倒顺序,但我也不太喜欢在同一脚本中混合 composepipe 。对于较长的 pipe 功能,我绝对更喜欢 convert。但是切换其中任何一个或组合它们都不会改变任何重要的内容。)

    重点是,这是建立在函数组合之上的。我并没有尝试一次性构建所有内容,而是编写单独的函数来完成小工作,然后将它们组合成更复杂的工作。

    请注意,此代码不会优雅地处理不良数据,并且更改为这样做可能会是一项繁重的工作。

    另请注意,在主函数中,我一次只执行一小步。我可以注释掉后续步骤以查看每个步骤的结果。我也可以使用 R.tap 如果我喜欢的话。

    重新组合很少是个好主意

    每个辅助函数,除了相对简单的 levelEq仅使用一次。所以它们可以很容易地内联。我们可以像这样重写这段代码:

    const convert = pipe(
    groupBy(pipe(prop('type'), find(pipe(prop('level'), equals(1))), propOr('NoName', 'name'))),
    map(pipe(pluck('type'), flatten, filter(pipe(prop('level'), gte(__, 2))), uniq)),
    toPairs,
    map(zipObj(['name', 'typechild']))
    );

    但对我来说,这是一个难以理解的困惑,我不会打扰。

    更好的文档

    如果您习惯了 Hindley-Milnar style type annotation ,它可能有助于向这些函数添加类型签名,也许类似于:

    // Type :: {name: String, level: Int}

    // :: Int -> (Type -> Bool)
    const levelEq = (n) => pipe(prop('level'), equals(n));
    // :: {type: [Type]} -> Type
    const topLevel = pipe(prop('type'), find(levelEq(1)));
    // :: {type: [Type]} -> String
    const topLevelName = pipe(topLevel, propOr('NoName', 'name'));
    // :: [{title: String, type: [Type}]}] -> [Type]
    const extract2ndLevel = pipe(pluck('type'), flatten, filter(levelEq(2)));

    // [{title: String, type: [Type]}] -> [{name: String, typechild: [Type]}]
    const convert = pipe( /* ... */ )

    (如果这些对您来说毫无意义,请不要担心。)

    更改输出格式

    但也许你真的想要这样的东西:

    [
    {"name": "Food", "typechild": ["Fruit", "Vegetable"]},
    {"name": "Entertainment", "typechild": ["Book", "Movie"]},
    {"name": "NoName", "typechild": ["Foo"]},
    {"name": "Bar", "typechild": []}
    ]

    事实证明这是一个简单的改变:

    const convert = pipe(
    groupBy(topLevelName),
    map(extract2ndLevel),
    map(uniq),
    map(pluck('name')), // <--- A single addition
    toPairs,
    map(zipObj(['name', 'typechild']))
    );

    map的优点

    我们在最后一个片段中看到的一件事是一系列连续的 map来电。其中每一个都单独循环列表。这使得代码干净,但是如果在性能测试中,您发现这个额外的循环导致了您的问题,您可以利用 composition law associated with map ,经过适当翻译后,它表示

    pipe(map(f), map(g)) ≍ map(pipe(f, g))

    所以你可以添加这个:

    // :: [{title: String, type: [Type}]}] -> [String]
    const foo = pipe(extract2ndLevel, uniq, pluck('name'));

    并像这样重写 main 函数:

    // [{title: String, type: [Type]}] -> [{name: String, typechild: [Type]}]
    const convert = pipe(
    groupBy(topLevelName),
    map(foo),
    toPairs,
    map(zipObj(['name', 'typechild']))
    );

    但事实上,我想不出这个新函数的好名字,这让我觉得它不是一个很好的抽象;只有当实际性能测试证明多次迭代是一个现实问题时,我才会选择这样做。

    结论

    函数式编程涉及很多事情,但关键技术之一是将所有内容不断分解为易于理解的部分。这就是我尝试用这个解决方案做的事情。虽然我们可以打破这个来创建没有依赖关系的单个函数(上面的“重新组合...”),但很少可读。另一方面,这种方法可以轻松改变我们的方法(“更改输出格式”),并且在必要时修复性能问题(map 的优点”)。

    哇,那应该是一篇博客文章!

    <小时/>

    您可以在 Ramda REPL 上看到其中的大部分内容。

    关于javascript - 访问 compose 函数 Ramda 内的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44669727/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com