[英]Map and filter an object using Ramda
I'm learning Ramda
and I'm a little confused how to build this lodash
chain below using Ramda
.我正在学习Ramda
和我有点困惑如何构建这个lodash
下面使用链Ramda
。 Ramda
returns functions for it's operations instead of actual values, and this seems to be the focal point of functional programming, however in this example I have a second parameter localRegex
that isn't a primary argument. Ramda
为其操作返回函数而不是实际值,这似乎是函数式编程的焦点,但是在这个示例中,我有第二个参数localRegex
,它不是主要参数。 It seems that it wouldn't be possible to get this to be completely duplicated without wrapping the Ramda
function and using .apply()
or .call()
to propagate the wrapped function arguments to the Ramda
function, which seems more complicated then using lodash
.它似乎不可能得到这个被完全复制,而不包裹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))
Here's what I've got and its not working.这是我所拥有的,但它不起作用。
var getRecursiveDeps = R.chain(
R.map(function(dependency){
return dependency.source.value
}),
R.filter(function(value){
return value.match(localRegex)
})
)
Is there a way to have Ramda
use a main variable for chaining and also pass down localRegex
?有没有办法让Ramda
使用主变量进行链接并传递localRegex
? Is there a way to duplicate the getRecursiveDeps
that uses lodash
in Ramda
?有没有办法复制的getRecursiveDeps
使用lodash
在Ramda
?
There's a lot of talk about how Ramda
is functional and underscore
and lodash
aren't.有一个关于如何谈了很多Ramda
是功能齐全, underscore
和lodash
都没有。 But in this case the getRecursiveDeps
is a function that returns a value from lodash
.但在这种情况下, getRecursiveDeps
是一个从lodash
返回值的lodash
。 When you create functions like this from lodash
or underscore
the result is the same, there's just more work when it comes to wrapping it, in this case what would be the perk using Ramda
over Lodash
?当您从创建一个这样的功能lodash
或underscore
的结果是一样的,当涉及到包装它,在这种情况下会怎样使用是振作但只是更多的工作Ramda
在Lodash
?
R.chain
does something completely different from _.chain
. R.chain
做了一些与_.chain
完全不同的_.chain
。 Its type, according to the current documentation, is (a -> [b]) -> [a] -> [b]
, though its actual type is more general.根据当前文档,它的类型是(a -> [b]) -> [a] -> [b]
,尽管它的实际类型更通用。 Think of it as a "flat-map" function.将其视为“平面地图”功能。
What you actually want here is R.compose
or its left-to-right equivalent R.pipe
.你真正想要的是R.compose
或其从左到右的等效R.pipe
。
If the goal of the function is to find local dependencies, it seems appropriate to me to embed the pattern in the function.如果函数的目标是找到局部依赖关系,我认为将模式嵌入到函数中似乎是合适的。 I would thus write:我会这样写:
// getLocalDeps :: [{ source :: { value :: String }}] -> [String]
const getLocalDeps =
R.pipe(R.map(R.path(['source', 'value'])),
R.filter(R.test(/^[.]{0,2}[/]/)));
getLocalDeps(items); // => ['./foo']
I'm a bit confused by the name getRecursiveDeps
as the function isn't recursive.我对名称getRecursiveDeps
有点困惑,因为该函数不是递归的。 getLocalDeps
seems more appropriate. getLocalDeps
似乎更合适。
If you'd like to parameterize the pattern, I suggest breaking getLocalDeps
into smaller pieces:如果您想参数化模式,我建议将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));
You could then define other functions in terms of these building blocks:然后,您可以根据这些构建块定义其他功能:
// 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$/)));
Another way to do this, points-free and preserving your existing API is like this:这样做的另一种方法,无积分并保留您现有的 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"]
The last line of the function feels a bit unfortunate to me, and this question has caused me to open an issue about reverting some recent changes to the library.函数的最后一行对我来说感觉有点不幸,这个问题让我打开了一个关于恢复最近对库的一些更改的问题。 There are several variants that could be used:有几种可以使用的变体:
// ...
R.pipe(regex => item => R.test(regex, item), R.filter)
//...
or或者
// ...
regex => R.filter(R.test(regex))
//...
But before a recent change to Ramda, it would have been simply但是在最近对 Ramda 进行更改之前,它会很简单
// ...
R.pipe(R.test, R.filter)
//...
One thing, though, is that Ramda tries hard to keep parameters in a logical order: with those less likely to change coming before those more likely to change.不过,有一件事是 Ramda 努力使参数保持在一个逻辑顺序中:那些不太可能改变的先于那些更有可能改变的。 With that in mind, I would prefer something like this:考虑到这一点,我更喜欢这样的事情:
// 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"]
And that feels cleaner still.那感觉仍然更干净。 Moreover, it lets you predefine the function and use it separately:此外,它允许您预定义函数并单独使用它:
myDeps = localDeps2(localRegex);
myDeps(items); //=> ["./foo"]
And that is a good part of what Ramda is about.这是 Ramda 的一个很好的部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.