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包.
Array.prototype.map和Array.prototype.find
看起来你对实现细节很顽固,但我确定你不知道为什么.有什么不妥for或while或filter.在这篇文章的最后,我不希望你相信我,相反,我希望你知道这是真的.
你可以平凡地使用map和解决这个问题find- 对于所有意图和目的,如何 实现map和find实施对你来说是个谜.如果他们使用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存在于第一个地方-同样也适用于for和while.
每次我想循环一个数组,或过滤一个数组,或在数组中找到一个元素,我都不想手工完成.我使用函数的原因是我不必重复自己......永远.
好奇心
所以也许你对上面的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的实现支持它.这意味着您编写的任何递归函数(除非您蹦蹦跳跳)都存在堆栈溢出的潜在风险.
这意味着实施与功能接口for和while是这么好很多.
下面,我们重新实现map,find但这次我们通过避免堆栈溢出的风险以一种聪明的方式做到这一点.请注意,它对结果代码没有任何影响.我们仍然可以互动map,并find在一个不错的,功能性的方式-他们俩都引用透明
特别注意main功能 - 它根本没有改变上面的例子.我们的"丑陋" while和for循环被巧妙地隐藏起来作为一个实现细节,最终用户不是更明智的.
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)