我有一个像这样的索引映射:
var idxMapping = {
abc: 1,
foo: 2,
bar: 0
};
一系列对象:
var data = [{
id: 'abc',
info1: 'random info 1',
info2: 'random info 2',
}, {
id: 'foo',
info1: 'random info 1',
info2: 'random info 2',
}]
使用函数式编程范例,我如何创建一个新数组,以便根据idxMapping中指定的索引转换数据。
结果应该类似于:
[
null,
{
id: 'abc',
info1: 'random abc info 1',
info2: 'random abc info 2'
},
{
id: 'foo',
info1: 'random foo info 1',
info2: 'random foo info 2'
}
]
第一个元素为null,因为数据数组不包含任何映射到索引0的数据(即本例中没有条形对象)。
这是我使用forEach循环实现的方式:
var result = [];
for (var key in idxMapping) {
result.append(null);
}
data.forEach(function(item) {
result[idxMapping[item.id]] = item;
});
我需要严格遵循函数式编程范例的解决方案。
答案 0 :(得分:4)
函数式编程风格中有一种可能的方法:
var idxMapping = {
abc: 1,
foo: 2,
bar: 0
};
var data = [{
id: 'abc',
info1: 'random info 1',
info2: 'random info 2',
}, {
id: 'foo',
info1: 'random info 1',
info2: 'random info 2',
}]
Object.keys(idxMapping)
.sort((fstKey, scndKey) => idxMapping[fstKey] - idxMapping[scndKey])
.map(key => data.find(el => el.id === key))
.map(el => !!el ? el : null)
或
Object.keys(idxMapping)
.sort((fstKey, scndKey) => idxMapping[fstKey] - idxMapping[scndKey])
.map(key => { var obj = data.find(el => el.id === key); return !!obj ? obj : null })
答案 1 :(得分:1)
可以这样做:
var result = data.reduce (
(acc, obj) => Object.assign(acc, { [idxMapping[obj.id]]: obj }),
Object.keys(idxMapping).map( _ => null) );
var idxMapping = {
abc: 1,
foo: 2,
bar: 0
};
var data = [{
id: 'abc',
info1: 'random info 1',
info2: 'random info 2',
}, {
id: 'foo',
info1: 'random info 1',
info2: 'random info 2',
}];
var result = data.reduce (
(acc, obj) => Object.assign(acc, { [idxMapping[obj.id]]: obj }),
Object.keys(idxMapping).map( _ => null) );
console.log(result);

这假设idxMapping
中提到的索引在0..n-1
范围内,其中 n 是该数组中元素的数量。
如果在结果数组中有undefined
而不是null
,那么Object.keys()
部分可以仅由[]
替换。
首先创建一个数组,其null
个条目与idxMapping
中的键一样多:
Object.keys(idxMapping).map( _ => null)
这成为reduce
的初始累加器值,然后迭代data
的每个元素。在每次迭代中,从idxMapping
:
idxMapping[obj.id]
使用computed property names的ES6语法,此值(数字)用作(累加器)数组对象的键(它实际上是数组的索引,但数组的索引本质上是对象属性):
[idxMapping[obj.id]]
...并在对象文字中为数据元素分配:
{ [idxMapping[obj.id]]: obj }
例如,上述内容可能会解决此问题:
{ '1': obj }
......还有:
{ '1': {
id: 'abc',
info1: 'random info 1',
info2: 'random info 2',
} }
然后使用Object.assign
:
Object.assign(acc, { [idxMapping[obj.id]]: obj })
...归结为将(累积)结果数组的一个条目设置为正确的值。继续上面的例子,你实际上得到了这个任务:
acc[1] = {
id: 'abc',
info1: 'random info 1',
info2: 'random info 2',
}
这个数组也是Object.assign
的返回值,这很好,因为reduce
期望内部回调函数返回累加器的新值,并在下一次迭代中将其传递回回调函数。
在最后一次迭代中,此返回值将成为reduce
本身的返回值,从而成为result
的值。
答案 2 :(得分:0)
我可以使用单个衬垫进行如下操作;
var idxMapping = {
abc: 1,
foo: 2,
bar: 0
},
data = [{
id: 'abc',
info1: 'random info 1',
info2: 'random info 2',
},
{
id: 'foo',
info1: 'random info 1',
info2: 'random info 2',
}],
result = data.reduce((p,c) => (p[idxMapping[c.id]]=c,p),Array(Math.max(...Object.values(idxMapping))+1).fill(null));
console.log(result);

对于FF v50和Chrone v53 ,
Object.values()
应该没问题
reduce Array(Math.max(...Object.values(idxMapping))+1).fill(null)
的初始部分只会在null
中创建一个大小为idxMapping + 1
s且大小最大值的数组,其余的只是缩小。