在给定数组的情况下提取对象值的功能方法

drh*_*lau 2 javascript functional-programming lodash ramda.js

我有一组键值对象,如下所示:

var d = [{'name':'a', 'value':1}, {'name':'b', 'value':2}, {'name':'c', 'value':3}, {'name':'d', 'value':4}, {'name':'e', 'value':5}, {'name':'f', 'value':6}]
Run Code Online (Sandbox Code Playgroud)

和一个数组

var a = ['a','e']
Run Code Online (Sandbox Code Playgroud)

如何编写一个提取值的函数,基本上是我想要的结果

[{'name':'a', 'value':1},{'name':'e', 'value':5} ]
Run Code Online (Sandbox Code Playgroud)

我想以纯粹的功能方式编写它,而不是使用for,while循环或filter函数.我想知道有没有一种正确有效的方法?以正确的方式递归?我打开使用lodash,ramda或任何其他FP包.

Tha*_*you 5

Array.prototype.map和Array.prototype.find

看起来你对实现细节很顽固,但我确定你不知道为什么.有什么不妥forwhilefilter.在这篇文章的最后,我不希望你相信我,相反,我希望你知道这是真的.

你可以平凡地使用map和解决这个问题find- 对于所有意图和目的,如何 实现mapfind实施对你来说是个谜.如果他们使用for循环甚至是GOTO大声呼喊并不重要.对您而言重要的是您能够以功能性的方式表达您的问题.

map并且find是卑微的JavaScript函数程序员的完美伴侣......

var d = [{'name':'a', 'value':1}, {'name':'b', 'value':2}, {'name':'c', 'value':3}, {'name':'d', 'value':4}, {'name':'e', 'value':5}, {'name':'f', 'value':6}]

var a = ['a','e']

var result = a.map(x => d.find(y => y.name === x))

console.log(result)
// [ { name: 'a', value: 1 },
//   { name: 'e', value: 5 } ]
Run Code Online (Sandbox Code Playgroud)


通用函数促进代码重用

使用一些通用函数,我们可以稍微更加可重用的方式表达解决方案

var data = [{'name':'a', 'value':1}, {'name':'b', 'value':2}, {'name':'c', 'value':3}, {'name':'d', 'value':4}, {'name':'e', 'value':5}, {'name':'f', 'value':6}]

const findBy = k => xs => v =>
  xs.find(x => x[k] === v)

const findAllBy = k => xs => vs =>
  vs.map(findBy(k)(xs))

console.log(findAllBy ('name') (data) (['a', 'e']))
// [ { name: 'a', value: 1 },
//   { name: 'e', value: 5 } ]
Run Code Online (Sandbox Code Playgroud)


为什么顽固无济于事

如果你想看到这是如何做到不依靠任何 for,while,filter,map,或find...

var data = [{'name':'a', 'value':1}, {'name':'b', 'value':2}, {'name':'c', 'value':3}, {'name':'d', 'value':4}, {'name':'e', 'value':5}, {'name':'f', 'value':6}]

const main = ([x,...xs]) => {
  const aux = ([y,...ys]) => {
    if (y === undefined)
      return null
    else if (y.name === x)
      return y
    else
      return aux (ys)
  }
  if (x === undefined)
    return []
  else
    return [aux(data), ...main(xs)]
}

console.log(main(['a', 'e']))
// [ { name: 'a', value: 1 },
//   { name: 'e', value: 5 } ]
Run Code Online (Sandbox Code Playgroud)

真痛苦啊?但此类代码小于其他的答案会在这里仍然有像依赖性length,indexOf,slice或整个lodash库.

所以真的没有意义这样做.在这个例子中编码了大量有用的泛型函数,我们希望在其他地方使用它们.这就是为什么功能,如map,reduce,filter,和find存在于第一个地方-同样也适用于forwhile.

每次我想循环一个数组,或过滤一个数组,或在数组中找到一个元素,我都不想手工完成.我使用函数的原因是我不必重复自己......永远.


好奇心

所以也许你对上面的map+ find解决方案没问题,但你也很好奇如果你已经没有它们可以自己实现它们了 - 下面只有2种无数的方法你可以实现这些功能之一.

var data = [{'name':'a', 'value':1}, {'name':'b', 'value':2}, {'name':'c', 'value':3}, {'name':'d', 'value':4}, {'name':'e', 'value':5}, {'name':'f', 'value':6}]

const find = f => ([x,...xs]) =>
  x === undefined ? null :
    f(x) === true ? x : find (f) (xs)

const map = f => ([x,...xs]) =>
  x === undefined ? [] : [f(x), ...map(f)(xs)]
  
const main =
  map (x => find (y => y.name === x) (data))
  
console.log(main(['a', 'e']))
// [ { name: 'a', value: 1 },
//   { name: 'e', value: 5 } ]
Run Code Online (Sandbox Code Playgroud)


递归很糟糕的JavaScript

很多人都不知道JavaScript中的递归是因为它实际上并不是很好.我们在ES6中得到了尾部调用消除的承诺,但目前没有JavaScript的实现支持它.这意味着您编写的任何递归函数(除非您蹦蹦跳跳)都存在堆栈溢出的潜在风险.

这意味着实施与功能接口forwhile这么好很多.

下面,我们重新实现map,find但这次我们通过避免堆栈溢出的风险以一种聪明的方式做到这一点.请注意,它对结果代码没有任何影响.我们仍然可以互动map,并find在一个不错的,功能性的方式-他们俩都引用透明

特别注意main功能 - 它根本没有改变上面的例子.我们的"丑陋" whilefor循环被巧妙地隐藏起来作为一个实现细节,最终用户不是更明智的.

var data = [{'name':'a', 'value':1}, {'name':'b', 'value':2}, {'name':'c', 'value':3}, {'name':'d', 'value':4}, {'name':'e', 'value':5}, {'name':'f', 'value':6}]

const find = f => xs => {
  for (let x of xs)
    if (f(x) === true)
      return x
  return null
}

const map = f => xs => {
  const acc = Array(xs.length)
  for (let [i,x] of xs.entries())
    acc[i] = f(x)
  return acc
}

const main =
  map (x => find (y => y.name === x) (data))
  
console.log(main(['a', 'e']))
// [ { name: 'a', value: 1 },
//   { name: 'e', value: 5 } ]
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案.让我们希望OP会认真对待你. (2认同)