简体   繁体   English

使用 Ramda 映射和过滤对象

[英]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使用lodashRamda

There's a lot of talk about how Ramda is functional and underscore and lodash aren't.有一个关于如何谈了很多Ramda是功能齐全, underscorelodash都没有。 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 ?当您从创建一个这样的功能lodashunderscore的结果是一样的,当涉及到包装它,在这种情况下会怎样使用是振作但只是更多的工作RamdaLodash

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM