我有一组键值对象,如下所示:
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']
如何编写一个提取值的函数,基本上是我想要的结果
[{'name':'a', 'value':1},{'name':'e', 'value':5} ]
我想以纯粹的功能方式编写它,而不是使用for
,while
循环或filter
函数。我想知道有没有一种正确有效的方法?以正确的方式递归?我愿意使用lodash
,ramda
或任何其他FP包。
答案 0 :(得分:5)
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 } ]

通用功能促进代码重用
使用一些通用函数,我们可以稍微更加可重用的方式表达解决方案
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 } ]

为什么顽固不帮助
如果您想要了解如何完成此操作,而不依赖于任何 for
,while
,filter
,map
或{{ 1}} ...
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 } ]
,length
,indexOf
或整个lodash lib等依赖项。
所以真的没有意义这样做。在这个例子中编码了大量有用的泛型函数,我们希望在其他地方使用它们。这就是为什么slice
,map
,reduce
和filter
等函数首先存在的原因 - 同样适用于find
和{{for
1}}。
每次我想循环一个数组,过滤数组,或者在数组中找到一个元素时,我都不想手工完成。我使用函数的原因是我不必重复自己......永远。
<强>好奇心强>
所以也许您可以使用上面的while
+ map
解决方案,但是您也很好奇如果您没有&#自己如何实施它们&#? 39;已经掌握了它们 - 下面只有2种无数方式可以实现这些功能。
find
&#13;
递归在JavaScript中很糟糕
许多人不了解JavaScript中的递归,实际上并不是很好。我们在ES6中得到了尾部调用消除的承诺,但目前没有JavaScript的实现支持它。这意味着您编写的任何递归函数(除非您蹦蹦跳跳)都存在堆栈溢出的潜在风险。这意味着实现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 } ]
和for
的功能接口所以更好。
下面,我们重新实现while
和map
,但这次我们通过避免堆栈溢出的风险以聪明的方式完成。请注意,它对结果代码没有任何影响。我们仍然可以通过良好,实用的方式与find
和map
进行互动 - 而且它们都是引用透明的
特别注意find
功能 - 它根本没有改变上面的例子。我们的丑陋&#34; main
和while
循环被巧妙地隐藏起来作为实现细节,最终用户不是更明智的。
for
&#13;
答案 1 :(得分:2)
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'];
d.filter(function(item){
return a.indexOf(item.name) > -1;
})
// will return [{'name':'a', 'value':1}, {'name':'b', 'value':5}]
希望这会有所帮助
答案 2 :(得分:1)
不幸的是,我必须使用R.map
,但使用Ramda
:
R.flatten(R.map(R.useWith(R.filter, [R.propEq('name'), R.identity])(R.__, d), a))
这是我能想到的,但我知道有更好的解决方案,我很乐意听到
编辑:我认为这个更好
R.filter(R.compose(R.flip(R.contains)(a), R.prop('name')), d)
答案 3 :(得分:0)
如果您希望您的解决方案是递归的,那么您需要这样的东西。
function getValues(objects, names, result) {
if (objects.length === 0 || names.length === 0) {
return result;
}
var index = names.indexOf(objects[0].name)
if (index > -1) {
result.push(objects[0]);
return getValues(objects.slice(1), [...names.slice(0, index), ...names.slice(index, names.length)], result);
} else {
return getValues(objects.slice(1), names, result);
}
}
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']
console.log(getValues(d, a, []));
答案 4 :(得分:-1)
我认为OP正在寻找类似的东西:
const _ = require('lodash');
function solve(array, keys) {
if (_.isEmpty(array) || _.isEmpty(keys)) {
return [];
} else {
const [ele, ...tailArray] = array;
const [key, ...tailKeys] = keys;
if (ele.name === key) {
return [ele, ...solve(tailArray, tailKeys)];
} else {
return solve(tailArray, keys);
}
}
}
const d = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}, {'name': 'c', 'value': 3}, {'name': 'd', 'value': 4}, {'name': 'e', 'value': 5}];
const a = ['a', 'e'];
console.log(solve(d, a));
这假定两个数组都已排序,所有名称都是唯一的,array a
中的所有元素也存在于array d
中。其他解决方案留给了@cherhan。