- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 Ramda 来为某些数据提供结构。但是,我无法访问 compose
内的数据。
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
,并颠倒顺序,但我也不太喜欢在同一脚本中混合 compose
和 pipe
。对于较长的 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/
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭去年。 Improve th
我正在尝试向嵌套对象添加新属性 width 和 height。 我的数据结构是这样的: const graph = { id: 'root', children: [ {
我正在尝试向嵌套对象添加新属性 width 和 height。 我的数据结构是这样的: const graph = { id: 'root', children: [ {
我想像这样计算三个数组。 const Data = { x : [2,4,6], y : [10,10,10], z : [5,5,5] } const XtimesYplusZ
转换以下对象的最简单方法是什么? // original { name: "bob", age: 24 } // result { name: "bob", age: 24, de
这是初始状态。 const All = { id : [ "a", "b", "c", "d", "e"], count : [1, 2, 2], } 我想把 All.id 拆分成 [ ["a
let arr = [ { name: 'Anna', q: { name: 'Jane' } } ]; const getName = R.prop('n
我有下面的代码,我想在其中填写id,所以我想写这样的东西: const data = [ { id: 'some-id' }, { id: 'some-other-id' }, { id: 't
我有一个类似这样的列表: var list = [ { stack: [ { file: 'abc' } ] }, { st
鉴于下面的功能,如何将其转换为无点样式?使用 Ramda 的 prop 会很好和 path并跳过数据参数,但我无法弄清楚正确的语法。 const mapToOtherFormat = (data) =
Ramda 适合懒人 Ramda 的 transduce启用 creation of lazy sequences . 一对多 R.chain可以在转换器中用作一对多运算符,如下所示 ( REPL )
Ramda 是否具有从列表中删除错误值的功能? 我知道我们可以简单地做 var compact = R.filter(R.identity);但我错过了现成的功能吗? 最佳答案 没有直接的等价物,但
我是 的新手 lambda 我正在努力实现以下目标: 我有一组对象(即消息)。 我想按对方 ID 对消息进行分组(发件人或收件人 ID,不是 1,请参阅下面的 groupBy lambda)。 我将获
我正在探索这两个库,对我来说 ImmutableJS具有(主要)不可变的数据结构,而 Ramda有瑞士军刀套装FP实用程序。 当我谷歌时,我看到类似 Ramda 的文章对比 ImmutableJS推荐
试图弄清楚 IO monad 是如何工作的。 使用下面的代码,我读取了 filenames.txt 并使用结果重命名目录 testfiles 中的文件。这显然是未完成的,所以我没有实际重命名我登录到控
我是 ramdajs 的新手。假设我有一个对象: {a: 1, b: 2, c: 3} 我可以这样做来将 a 更改为 11: const aLens = R.lensProp('a'); R.
我想从对象中删除所有空值。让我们假设: const data = { key1: 'ok', key2: null, key3: '', // should be removed too
我有两个柯里化(Currying)函数 f 和 g: f: a -> b -> c g: a -> c -> d 我想创建h: h: a -> b -> d 目前我正在通过 pipe 编写它们: co
我很想学习 js 中的函数式编程,但是我遇到了困难。我觉得我一直在做这样的事情,这感觉根本不对: export const getParamFromUrl = R.curry((name, url)
我试图将一个函数传递到一个过滤器中,该过滤器本身嵌套在更深的函数中 从概念上讲,类似于这个(损坏的)示例: const testData = [ {foo: "foo", bar: ""} ];
我是一名优秀的程序员,十分优秀!