2012-03-12 26 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

相关问题