2012-03-12 25 views
1
var array1 = [{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}]; 
var array2 = [{ "name" : "foo" , "age" : "22"}, { "name" : "buz" , "age" : "35"}]; 

什麼是最快的方法有(無重複,名字是標識符):在Javascript中,如何合併對象數組?

[{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}, { "name" : "buz" , "age" : "35"}]; 

有和沒有的jQuery如果可能的話。

+0

可能的重複[如何合併兩個數組在Javascript](http://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript) – 2012-03-12 17:27:22

+2

什麼是每個元素的唯一標識符? 「a」,「b」或「c」或「name」屬性? – Matt 2012-03-12 17:27:35

+0

此外,即使對象是相同的,它們也不是同一個對象,因此不會被視爲重複對象。 – lonesomeday 2012-03-12 17:28:40

回答

5

這是一個通用函數,它可以合併任意數量的數組,防止傳入的鍵的重複。

當它合併時,它會創建一個到目前爲止使用的名稱的臨時索引,並且只合並具有唯一名稱的新元素。這個臨時索引應該比通過結果進行線性搜索快得多,特別是在數組變大時。作爲該方案的一個功能,它可以過濾所有重複項,甚至可能位於其中一個源數組中的重複項。

如果一個元素沒有密鑰名,它是跳過(雖然這一邏輯可以顛倒,如果你想這取決於什麼錯誤處理您想爲):

var array1 = [{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}]; 
var array2 = [{ "name" : "foo" , "age" : "22"}, { "name" : "buz" , "age" : "35"}]; 

function mergeArrays(keyName /* pass arrays as additional arguments */) { 
    var index = {}, i, len, merge = [], arr, name; 

    for (var j = 1; j < arguments.length; j++) { 
     arr = arguments[j]; 
     for (i = 0, len = arr.length; i < len; i++) { 
      name = arr[i][keyName]; 
      if ((typeof name != "undefined") && !(name in index)) { 
       index[name] = true; 
       merge.push(arr[i]); 
      } 
     } 
    } 
    return(merge); 
} 

var merged = mergeArrays("name", array1, array2); 

// Returns: 
// [{"name":"foo","age":"22"},{"name":"bar","age":"33"},{"name":"buz","age":"35"}] 

你可以看到它在這裏工作:http://jsfiddle.net/jfriend00/8WfFW/

當該算法在使用較大的陣列jsperf靠在馬特算法運行,此算法是圍繞要快20倍:

enter image description here

+0

添加[jsPerf測試結果](http://jsperf.com/merge-arrays)比較此算法與Matt提出的一種方法(使用javascript對象進行線性搜索與哈希查找)。 – jfriend00 2012-03-12 23:06:28

+0

謝謝,這太神奇了 – 2012-03-13 09:55:05

0

我不認爲簡單的JavaScript提供比迭代數組和手動實現邏輯的更好的東西。我會建議的是使用awk的underscore.js庫,它提供了許多功能類似的工具來處理數組和集合;爲您解決例如問題這可能是工作:

http://documentcloud.github.com/underscore/#union

jQuery是另一種選擇,但它更是一個DOM操縱面向瀏覽器庫,而下劃線作出處理這些類型的問題。

-3

我能想到的第一種方式:

array3 = []; 
for(object in array1) { 
    var match=false; 
    for(already in array3) { 
     if (already==object) { 
      match=true; 
      break; } } 
    if (match) array3.push(object); } 
+1

這不會作爲*所有*對象不同;他們只是*相同*因爲他們有相似的成員/屬性。 '已經==對象'永遠不會評估爲'真正' – Matt 2012-03-12 17:31:33

+0

不要爲數組「換入」。改用Array的'for'和'.length'來代替。 – 2012-03-12 17:31:42

+1

@Matt:實際上,他是比較屬性名稱而不是值......但是無論如何,這是完全錯誤的。它的工作原理是 – 2012-03-12 17:35:42

1

你有什麼是完全不同的對象,並沒有什麼內置到JavaScript檢測相同對象;它具有相同的屬性,即對象,所以我們必須寫我們自己的函數:

function merge(set1, set2) { 
    // Already put the elements of set1 in the result array 
    // see Array.slice 
    var result = set1.slice(0); 

    // Utility function which iterates over the elements in result 
    // and returns true if an element with the same name already 
    // exists. false otherwise 
    function exists(obj) { 
     for (var i=0;i<result.length;i++) { 
      if (result[i].name == obj.name) { 
       return true; 
      } 
     } 

     return false; 
    } 

    // Now simply iterate over the second set and add elements 
    // which aren't there already using our exists() function. 
    for (var i=0;i<set2.length;i++) { 
     if (!exists(set2[i])) { 
      result.push(set2[i]); 
     } 
    } 

    return result; 
} 

你會再與調用它;

var result = merge(array1, array2); 

要變得對對象平等更有信心,請嘗試以下實驗;

var a = { "test": 1 }; 
var b = { "test": 1 }; 
var aClone = a; 

alert(a == a); // true 
alert(a == b); // false 
alert(a == aClone); // true 
+0

。謝謝。 – 2012-03-12 17:43:20

+2

OP要求「最快」的方式來做到這一點。我相當懷疑在結果數組中對現有名稱進行線性搜索是檢測嘟fastest的最快方法。使用一個對象(本質上是一個具有唯一鍵的散列表)是一種快速跟蹤結果中已經存在哪些項目的方法。請參閱[此答案](http://stackoverflow.com/a/9672050/816620)該類型的實現。 – jfriend00 2012-03-12 17:52:56

相關問題