高效连接两个集合
Joining two collections efficiently?
我遇到了一个问题,我正在尝试连接两个类似于下面的数组:
var participants = [
{id: 1, name: "abe"},
{id:2, name:"joe"}
];
var results = [
[
{question: 6, participantId: 1, answer:"test1"},
{question: 6, participantId: 2, answer:"test2"}
],
[
{question: 7, participantId: 1, answer:"test1"},
{question: 7, participantId: 2, answer:"test2"}
]
];
使用嵌套循环:
_.each(participants, function(participant) {
var row, rowIndex;
row = [];
var rowIndex = 2
return _.each(results, function(result) {
return _.each(result, function(subResult) {
var data;
data = _.find(subResult, function(part) {
return part.participantId === participant.id;
});
row[rowIndex] = data.answer;
return rowIndex++;
});
});
});
只要数组很小,这就可以正常工作,但是一旦它们变大,我就会遇到巨大的性能问题。 有没有更快的方法以这种方式组合两个数组?
这是我真实数据集/代码的精简版本。 如果有什么没有意义的,请告诉我。
仅供参考
我的最终目标是为每个参与者创建一个包含其答案的行集合。 像这样:
[
["abe","test1","test1"],
["joe","test2","test2"]
]
perf* 不是来自 for 循环,所以如果它们让你失望,你可以将它们更改为 _ 迭代
var o = Object.create(null);
for( var i = 0, len = participants.length; i < len; ++i ) {
o[participants[i].id] = [participants[i].name];
}
for( var i = 0, len = results.length; i < len; ++i ) {
var innerResult = results[i];
for( var j = 0, len2 = innerResult.length; j < len2; ++j) {
o[innerResult[j].participantId].push(innerResult[j].answer);
}
}
//The rows are in o but you can get an array of course if you want:
var result = [];
for( var key in o ) {
result.push(o[key]);
}
*好吧,如果 _ 使用本机 .forEach,那么这很容易比 for 循环慢几个数量级,但你的问题仍然是现在的 4 个嵌套循环,所以你甚至可能不需要额外的 10 倍修复后。
下面是使用 ECMA5 方法的解决方案
爪哇语
var makeRows1 = (function () {
"use strict";
function reduceParticipants(previous, participant) {
previous[participant.id] = [participant.name];
return previous;
}
function reduceResult(previous, subResult) {
previous[subResult.participantId].push(subResult.answer);
return previous;
}
function filterParticipants(participant) {
return participant;
}
return function (participants, results) {
var row = participants.reduce(reduceParticipants, []);
results.forEach(function (result) {
result.reduce(reduceResult, row);
});
return row.filter(filterParticipants);
};
}());
这不会像@Esailija答案那样使用原始for
循环那么快,但它并不像您想象的那么慢。它肯定比使用 Underscore
更快,就像你的例子或 @Maroshii 给出的答案
无论如何,这里有一个所有三个答案的jsFiddle,证明它们都给出了相同的结果。它使用相当大的数据集,我不知道它与您使用的大小相比。数据生成如下:
爪哇语
function makeName() {
var text = "",
possible = "abcdefghijklmnopqrstuvwxy",
i;
for (i = 0; i < 5; i += 1) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
var count,
count2,
index,
index2,
participants = [],
results = [];
for (index = 0, count = 1000; index < count; index += 4) {
participants.push({
id: index,
name: makeName()
});
}
for (index = 0, count = 1000; index < count; index += 1) {
results[index] = [];
for (index2 = 0, count2 = participants.length; index2 < count2; index2 += 1) {
results[index].push({
question: index,
participantId: participants[index2].id,
answer: "test" + index
});
}
}
最后,我们有一个jsperf来比较这三种方法,在生成的数据集上运行。
尚未使用大量数据对其进行测试,但这里有一种方法:
var groups = _.groupBy(_.flatten(results),'participantId');
var result =_.reduce(groups,function(memo,group) {
var user = _.find(participants,function(p) { return p.id === group[0].participantId; });
var arr = _.pluck(group,'answer');
arr.unshift(user.name);
memo.push(arr);
return memo ;
},[]);
组的数量将是您将拥有的数组数量,因此然后迭代它而不会呈指数增长,就好像您调用_.each(_.each(_.each
一样,这可能非常昂贵。
再次,应该进行测试。
相关文章:
- 两个集合mongodb之间的关系
- 如何将两个集合转换为一个集合
- Meteor:如何使用空格键创建包含两个集合数据的树列表
- 如何计算mongodb中两个集合中一个字段的不同值的数量
- Metero 通过 id 从两个集合映射中获取数据
- 高效连接两个集合
- 主干集合 - 在集合级别合并两个集合
- 流星:如何在MongoDB中单击一下即可从两个集合中删除两个文档
- 如何在单个反应表中使用两个集合
- 在两个集合之间传递数据 - Meteor JS
- 合并两个集合在 mongodb 中没有地图减少....
- 从mongodb中的两个集合中的find生成一个json
- 通过两个集合来定义关系
- 两个集合通过iron:router显示在URL中
- Meteor计算两个集合的值
- MongoDB-插入到两个集合中,一个集合引用另一个作为子文档
- Lodash / javascript:比较两个集合并返回差异
- 主干:保持两个集合同步
- Mongo:获取两个集合的数据——第二个集合取决于第一个集合
- 在MongoDb中找到两个集合之间的交集