Yco*_*con 0 javascript ramda.js
我正在使用Ramda来提供一些数据的结构。但是,我一直无法访问中的数据compose。
level大于2的项目,但这不起作用[keys, compose(map(map(find(propEq('level', > 2)))), values)]
typeChild为unique。这是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)
Run Code Online (Sandbox Code Playgroud)
[{
"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}]
}
];
Run Code Online (Sandbox Code Playgroud)
[
{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: []}
]
Run Code Online (Sandbox Code Playgroud)
好吧,我将猜测您要寻找的东西。
首先,您确实需要演示输入数据的一部分。我将其简化为:
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}]
}
];
Run Code Online (Sandbox Code Playgroud)
(请注意,我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: []}
]
Run Code Online (Sandbox Code Playgroud)
这是一种方法:
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)
Run Code Online (Sandbox Code Playgroud)
(通常,对于那些单行代码,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']))
);
Run Code Online (Sandbox Code Playgroud)
但是对我来说这是一个难以理解的混乱,我不会打扰。
如果您习惯了Hindley-Milnar样式类型注释,则可能有助于向这些函数添加类型签名,也许类似:
// 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( /* ... */ )
Run Code Online (Sandbox Code Playgroud)
(如果这些对您没有任何意义,请不要担心。)
但是也许您真的想要这样的事情:
[
{"name": "Food", "typechild": ["Fruit", "Vegetable"]},
{"name": "Entertainment", "typechild": ["Book", "Movie"]},
{"name": "NoName", "typechild": ["Foo"]},
{"name": "Bar", "typechild": []}
]
Run Code Online (Sandbox Code Playgroud)
原来这是一个简单的更改:
const convert = pipe(
groupBy(topLevelName),
map(extract2ndLevel),
map(uniq),
map(pluck('name')), // <--- A single addition
toPairs,
map(zipObj(['name', 'typechild']))
);
Run Code Online (Sandbox Code Playgroud)
map我们在最后一个片段中看到的一件事是一系列连续的map调用。这些中的每一个都单独遍历该列表。这样可以生成清晰的代码,但是如果在性能测试中发现此附加循环导致了问题,则可以利用与map相关联的合成法则,该法则经过适当翻译后表示:
pipe(map(f), map(g)) ? map(pipe(f, g))
Run Code Online (Sandbox Code Playgroud)
因此,您可以添加以下内容:
// :: [{title: String, type: [Type}]}] -> [String]
const foo = pipe(extract2ndLevel, uniq, pluck('name'));
Run Code Online (Sandbox Code Playgroud)
并像这样重写主要功能:
// [{title: String, type: [Type]}] -> [{name: String, typechild: [Type]}]
const convert = pipe(
groupBy(topLevelName),
map(foo),
toPairs,
map(zipObj(['name', 'typechild']))
);
Run Code Online (Sandbox Code Playgroud)
但是我不能为这个新函数想到一个好名字,这使我认为这不是一个很好的抽象。仅当实际性能测试表明多次迭代是一个实际问题时,我才会选择这样做。
函数式编程涉及很多事情,但是关键技术之一就是将所有内容不懈地分解为易于理解的部分。这就是我尝试使用此解决方案的方法。虽然我们可以打破它来创建没有依赖性的单个函数(上面的“ Recombining ...”),但很少能读取。另一方面,这种方法使更改方法(“更改输出格式”)变得容易,并且在必要时解决了性能问题(“优点map”)。
哇,那应该是博客文章!
您可以在Ramda REPL上看到其中的大部分内容。
| 归档时间: |
|
| 查看次数: |
245 次 |
| 最近记录: |