2013-10-24 36 views
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++; 
    }); 
    }); 
}); 

這隻要陣列小工程確定,但是一旦它們變大,我就會遇到巨大的性能問題。以這種方式組合兩個數組有沒有更快的方法?

這是我的真實數據集/代碼的瘦身版本。請讓我知道是否有任何意義。

FYI

我的最終目標是創建行的集合包含他們的回答每一個參與者。喜歡的東西:

[ 
    ["abe","test1","test1"], 
    ["joe","test2","test2"] 
] 
+0

是的,我繼續添加它。 –

+0

標籤離開,這是非常強調 –

+0

@AbeMiessler可以安全地說,參與者集合是一個更小的數據陣列?或者是相反的? –

回答

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那麼這很容易數量級比循環要慢,但你現在的問題仍然是4個嵌套循環,所以你可能在修復之後甚至不需要額外的10倍。

+0

這將是非常難以改善,性能明智。 +1 – Xotic750

+0

要將o的屬性轉儲到結果數組中,您不希望在此使用hasOwnProperty警衛嗎?或用Object.create(null)創建o; – Kastor

+0

@Kastor如果您確定自己處於一個無所事事的環境中,並且擁有一個不受干擾的「Object」,那麼它絕對沒問題。如果你不確定那是,那麼把它包起來。 'hasOwnProperty'是一個相對昂貴的調用,它將對這個例程的性能產生顯着的影響,特別是在較舊的瀏覽器上,但在現代瀏覽器上尤其如此。 [jsPerf](http://jsperf.com/with-and-without-hasownproperty)。使用Object.create會限制這個例程只能在現代瀏覽器上使用,所以可能不是一個好的解決方案。 – Xotic750

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這可能是相當昂貴的。

再次,應該測試。

+2

最初的功能不起作用,所以任何功能無限快。儘管如此,請查看jsperf測試Xotic750:http://jsperf.com/make-rows-comparison/3 – Kastor

+0

好東西...接受的答案顯然是最好的解決方案 – Maroshii

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這三種方法,對所生成的數據集運行進行比較。

+0

我更新了您的jsperf示例以顯示原始功能不起作用,並反映Esailija的更新。 – Kastor

+1

看起來像你的答案是IE 10更快,Esailija的是在Firefox 24 – Kastor

+0

更快@Kastor哇,這是相當令人印象深刻! (我不是MS粉絲)。 – Xotic750