功能javascript根据一些映射重新排列数组索引

时间:2016-10-09 19:10:33

标签: javascript arrays functional-programming lodash data-manipulation

我有一个像这样的索引映射:

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;
});

我需要严格遵循函数式编程范例的解决方案。

3 个答案:

答案 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且大小最大值的数组,其余的只是缩小。