使用Ramda映射和过滤对象
Map and filter an object using Ramda
我正在学习Ramda
,我有点困惑如何使用Ramda
构建下面的lodash
链。Ramda
为它的操作返回函数,而不是实际值,这似乎是函数式编程的焦点,但是在这个例子中,我有第二个参数localRegex
,它不是主要参数。如果不包装Ramda
函数并使用.apply()
或.call()
将包装的函数参数传播给Ramda
函数,似乎不可能完全复制这一点,这似乎比使用lodash
更复杂。
var _ = require("lodash")
var R = require("ramda")
var localRegex = /^.'.'/|^.'/|^'//
function getRecursiveDeps(deps, localRegex){
return _.chain(deps)
.map(function(dep){
return dep.source.value
})
.filter(function(dep){
return dep.match(localRegex)
})
.value()
}
var items = [
{
"source": {
"value": "./foo"
}
},
{
"source": {
"value": "bar"
}
}
]
console.log(getRecursiveDeps(items, localRegex))
这是我得到的,它不能工作。
var getRecursiveDeps = R.chain(
R.map(function(dependency){
return dependency.source.value
}),
R.filter(function(value){
return value.match(localRegex)
})
)
是否有办法让Ramda
使用一个主变量链接,也传递localRegex
?有没有办法复制getRecursiveDeps
,在Ramda
中使用lodash
?
关于Ramda
的功能和underscore
和lodash
的功能有很多讨论。但在本例中,getRecursiveDeps
是一个返回lodash
值的函数。当你从lodash
或underscore
创建这样的函数时,结果是一样的,只是在包装它时需要更多的工作,在这种情况下,使用Ramda
比Lodash
有什么好处?
R.chain
做的事情与_.chain
完全不同。根据当前的文档,它的类型是(a -> [b]) -> [a] -> [b]
,尽管它的实际类型更为通用。把它想象成一个"平面地图"。函数。
这里实际需要的是R.compose
或从左到右的等效R.pipe
。
如果函数的目标是查找本地依赖项,那么在函数中嵌入模式对我来说似乎是合适的。我将这样写:
// getLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalDeps =
R.pipe(R.map(R.path(['source', 'value'])),
R.filter(R.test(/^[.]{0,2}[/]/)));
getLocalDeps(items); // => ['./foo']
我有点困惑的名称getRecursiveDeps
作为函数不是递归的。getLocalDeps
似乎更合适。
如果你想参数化模式,我建议将getLocalDeps
分解成更小的部分:
// isLocal :: String -> Boolean
const isLocal = R.test(/^[.]{0,2}[/]/);
// getDeps :: [{ source :: { value :: String }}] -> [String]
const getDeps = R.map(R.path(['source', 'value']));
// getLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalDeps = R.pipe(getDeps, R.filter(isLocal));
然后,您可以根据这些构建块定义其他函数:
// getNonLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getNonLocalDeps = R.pipe(getDeps, R.reject(isLocal));
// getLocalJsonDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalJsonDeps = R.pipe(getLocalDeps, R.filter(R.test(/[.]json$/)));
另一种方法是这样做的,无点且保留现有的API:
// getLocalDeps :: [{ source :: { value :: String }}] -> RegExp -> [String]
const getLocalDeps = R.useWith(
R.flip(R.call),
R.map(R.path(['source', 'value'])),
R.pipe(R.unary(R.test), R.filter)
);
localDeps(items, localRegex); //=> ["./foo"]
函数的最后一行对我来说感觉有点不太好,这个问题导致我打开了一个关于恢复对库的一些最近更改的问题。有几个变体可以使用:
// ...
R.pipe(regex => item => R.test(regex, item), R.filter)
//...
或
// ...
regex => R.filter(R.test(regex))
//...
但是在最近对Ramda进行更改之前,它应该是简单的
// ...
R.pipe(R.test, R.filter)
//...
然而,有一件事是,Ramda努力保持参数的逻辑顺序:那些不太可能改变的出现在那些更可能改变的之前。考虑到这一点,我更喜欢这样:
// getLocalDeps :: RegExp -> [{ source :: { value :: String }}] -> [String]
var getLocalDeps2 = R.useWith(
R.call,
R.pipe(R.unary(R.test), R.filter),
R.map(R.path(['source', 'value']))
);
localDeps2(localRegex, items); //=> ["./foo"]
感觉更干净了。此外,它允许您预定义函数并单独使用它:
myDeps = localDeps2(localRegex);
myDeps(items); //=> ["./foo"]
- 执行过滤对象数组的方法
- 如何按数组/对象值的倍数过滤对象数组
- 访问KendoUI中Datasource过滤对象的字段
- 通过 nodejs 过滤对象数组
- 如何过滤对象内部深度堆叠的数据(并在之后编辑删除它)
- 如何使用filter函数在javascript中过滤对象
- Javascript:按字符串数组过滤对象数组
- 按对象属性过滤对象的角度
- RXJS5 - 按每个对象包含的可观察性过滤对象数组
- 通过使用 AngularJS 遵循 OR 运算符仅过滤对象中的特定字段
- 在 lodash 中按键过滤对象
- Javascript 过滤对象
- Javascript - 如何按参数过滤对象数组
- 使用过滤器和下划线过滤对象数组
- 过滤对象数组时的无限$digest循环
- 使用Moment.js按“上个月”和“上周”单击时过滤对象数组
- 如何在 javascript 中过滤对象中具有特定后缀的键/值
- 按对象的属性过滤对象的 JavaScript 数组并删除重复项
- 对于循环中仅过滤对象
- 通过ng repeat内的关键帧过滤对象