arr1 = [
{ id : 1,
name : 'book1',
description: 'some text'
},
{ id : 2,
name : 'book2',
description: 'some text'
},
{ id : 3,
name : 'book3',
description: 'some text'
}
]
arr2 = [
{ id : 1,
name : 'book1',
type : 'thriller',
publisher : 'some x',
isbn : '2983457928435',
date : '20-1-2014'
},
{ id : 2,
name : 'book2',
type : 'action',
publisher : 'some x',
isbn : '2983457928435',
date : '20-1-2014'
},
{ id : 3,
name : 'book3',
type : 'thriller',
publisher : 'some y',
isbn : '2983457928435',
date : '20-1-2014'
}
]
我想基于id值将字段'type'和'publisher'分配给arr1,并并行地希望基于type的数组。
所需的输出是
arr3 = {
'thriller': [
{ id: 1, name: 'book1', type: 'thriller', publisher: 'some x', description: 'some text' },
{ id: 3, name: 'book3', type: 'thriller', publisher: 'some y', description: 'some text' }
],
'action': [
{ id: 2, name: 'book2', type: 'action', publisher: 'some x', description: 'some text' }]
}
性能是关键问题。我可以使用2个功能来实现上述目的,但我想用单个功能来实现。
Edit1:-在arr1和上面的字段中,我从database(mongodb)获取了其他字段。为简单起见,我包括了必需品。
目前,我通过以下2种功能实现此目标
功能1:-
let result = arr1.map((e) => {
for(let element of arr2){
if(e.id === element.id)
{
e['type'] = element.type
e['publisher'] = element.publisher
}
}
return e
})
功能2:-
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
var key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
let output = groupBy(result, 'type');
我想要的是将两种功能结合在一起,并在单个函数调用中执行。
答案 0 :(得分:1)
执行此操作后,我可以想象的唯一明显的性能问题就会出现:
arr1.reduce(function (acc, e) {
for (let element of arr2) {
/* ... */
}
})
这个嵌套循环大大提高了迭代次数。对于arr1
的每个元素,我们(潜在地)循环arr2
的每个元素,从而为我们提供了arr1.length
(最佳情况)和arr1.length * arr2.length
(最坏情况)之间的多次迭代。 )。如果您使用的是非常大的数据集,那么这种差异可能会很明显...
通常,解决方案是将数组索引到对象或映射中,从而可以更快地进行查找。转换数组需要一些时间,但是循环会运行得更快。
这是我在项目符号中的建议:
arr1
转换为以下形式的索引bookDescriptions
:{ id: { name, id, description } }
arr2
转换为以下形式的索引bookMetadata
:{id: { name, id, type, publisher } }
books
dat并按ID将其合并到:[ { name, id, type, description, publisher } ]
groupBy
进行最终分组在代码中:
// Index an array of values by a unique property
const indexBy = (k, xs) => xs.reduce(
(acc, x) => Object.assign(acc, { [x[k]]: x }),
{}
);
// Group an array of objects by a certain property
const groupBy = (k, xs) => xs.reduce(
(acc, x) => Object.assign(acc, {
[x[k]]: acc[x[k]]
? acc[x[k]].concat(x)
: [x]
}),
{}
);
// Return array without duplicates
const uniques = xs => Array.from(new Set(xs));
// Merge two indexes by their keys using Object.assign
const mergeIndexes = (i1, i2) =>
uniques([
...Object.keys(i1),
...Object.keys(i2)
]).map(k => Object.assign({}, i1[k], i2[k]));
const bookDescriptions = indexBy("id", getDescriptions());
const bookMetadata = indexBy("id", getMetadata());
const books = mergeIndexes(bookDescriptions, bookMetadata);
const booksByType = groupBy("type", books);
console.log(booksByType);
function getDescriptions() { return [{id:1,name:"book1",description:"some text"},{id:2,name:"book2",description:"some text"},{id:3,name:"book3",description:"some text"}]; };
function getMetadata() { return [{id:1,name:"book1",type:"thriller",publisher:"some x"},{id:2,name:"book2",type:"action",publisher:"some x"},{id:3,name:"book3",type:"thriller",publisher:"some y"}]; };
如果这仍然给您带来性能问题,您可以考虑微优化,例如合并功能,组合步骤等(但我不希望您需要这样做)
编辑:供参考,这是与1000本书的嵌套循环方法相比的索引方法的性能。我的机器的性能提高了大约10倍...
// Index an array of values by a unique property
const indexBy = (k, xs) => xs.reduce(
(acc, x) => Object.assign(acc, { [x[k]]: x }),
{}
);
// Group an array of objects by a certain property
const groupBy = (k, xs) => xs.reduce(
(acc, x) => Object.assign(acc, {
[x[k]]: acc[x[k]]
? acc[x[k]].concat(x)
: [x]
}),
{}
);
// Return array without duplicates
const uniques = xs => Array.from(new Set(xs));
// Merge two indexes by their keys using Object.assign
const bookMerger = (
{ name, id, description},
{ type, publisher }) => (
{ name, id, description, type, publisher }
);
const mergeIndexes = (i1, i2) =>
uniques([
...Object.keys(i1),
...Object.keys(i2)
]).map(k => bookMerger(i1[k], i2[k]));
console.time("indexed approach");
const bookDescriptions = indexBy("id", getDescriptions());
const bookMetadata = indexBy("id", getMetadata());
const books = mergeIndexes(bookDescriptions, bookMetadata);
const booksByType = groupBy("type", books);
console.timeEnd("indexed approach");
console.time("nested loop approach");
let result = getDescriptions().reduce(function (acc, e) {
let arr2 = getMetadata();
for(let element of arr2){
if(e.id === element.id)
{
e['type'] = element.type
e['publisher'] = element.publisher
break
}
}
var key = e['type'];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(e);
return acc;
}, {});
console.timeEnd("nested loop approach");
function getDescriptions() { return Array.from(
Array(1000),
(_, i) => (
{id:i, name:"book1", description:"some text"})
);
}
function getMetadata() { return Array.from(
Array(1000),
(_, i) => (
{id:i,name:"book1",type:"thriller",publisher:"some x"}
));
};
答案 1 :(得分:0)
arr1 = [
{ id : 1,
name : 'book1',
description : 'Some text here'
},
{ id : 2,
name : 'book2',
description : 'Some text here'
},
{ id : 3,
name : 'book3',
description : 'Some text here'
}
]
arr2 = [
{ id : 1,
name : 'book1',
type : 'thriller',
publisher : 'some x'
},
{ id : 2,
name : 'book2',
type : 'action',
publisher : 'some x'
},
{ id : 3,
name : 'book3',
type : 'thriller',
publisher : 'some y'
}
]
let result = arr1.reduce(function (acc, e) {
for(let element of arr2){
if(e.id === element.id)
{
e['type'] = element.type
e['publisher'] = element.publisher
break
}
}
var key = e['type'];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(e);
return acc;
}, {});
console.log(result)
我最终得到了上述解决方案。