0

我遇到了一个问题,我试图加入两个类似于以下数组的数组:

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"]
]
4

3 回答 3

3

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 倍。

于 2013-10-24T19:25:14.197 回答
1

这是使用 ECMA5 方法的解决方案

Javascript

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

这不会像使用原始for循环那样快,比如@Esailija 的回答,但它并不像你想象的那么慢。它肯定比使用更快Underscore,例如您的示例或@Maroshii 给出的答案

无论如何,这是所有三个答案的jsFiddle,证明它们都给出了相同的结果。它使用了相当大的数据集,我不知道它与您使用的大小相比。数据生成如下:

Javascript

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 ,在生成的数据集上运行。

于 2013-10-25T01:45:39.713 回答
0

尚未使用大量数据对其进行测试,但这是一种方法:

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这可能非常昂贵。

再次,应该进行测试。

于 2013-10-24T22:28:01.927 回答