代码之家  ›  专栏  ›  技术社区  ›  Vijjendra

如何在javascript中合并两个数组并消除重复项

  •  1098
  • Vijjendra  · 技术社区  · 16 年前

    我有两个javascript数组:

    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    

    我希望输出为:

    var array3 = ["Vijendra","Singh","Shakya"];
    

    输出数组应删除重复的字。

    如何在javascript中合并两个数组,以便仅从每个数组中按插入原始数组的相同顺序获取唯一项?

    70 回复  |  直到 7 年前
        1
  •  1371
  •   Bruno João    8 年前

    只合并数组(不删除重复项)

    ES5版本使用 Array.concat :

    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    
    var array3 = array1.concat(array2); // Merges both arrays
    // [ 'Vijendra', 'Singh', 'Singh', 'Shakya' ]
    

    ES6版本使用 destructuring

    const array1 = ["Vijendra","Singh"];
    const array2 = ["Singh", "Shakya"];
    const array3 = [...array1, ...array2];
    

    因为没有“内置”方式来删除重复项( ECMA-262 其实有 Array.forEach 这很好),我们必须手动完成:

    Array.prototype.unique = function() {
        var a = this.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }
    
        return a;
    };
    

    然后,要使用它:

    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    // Merges both arrays and gets unique items
    var array3 = array1.concat(array2).unique(); 
    

    这还将保留数组的顺序(即,不需要排序)。

    因为很多人对 Array.prototype for in 循环,这里是一种侵入性较低的使用方法:

    function arrayUnique(array) {
        var a = array.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }
    
        return a;
    }
    
    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
        // Merges both arrays and gets unique items
    var array3 = arrayUnique(array1.concat(array2));
    

    对于那些有幸使用ES5的浏览器的人,您可以使用 Object.defineProperty 这样地:

    Object.defineProperty(Array.prototype, 'unique', {
        enumerable: false,
        configurable: false,
        writable: false,
        value: function() {
            var a = this.concat();
            for(var i=0; i<a.length; ++i) {
                for(var j=i+1; j<a.length; ++j) {
                    if(a[i] === a[j])
                        a.splice(j--, 1);
                }
            }
    
            return a;
        }
    });
    
        2
  •  533
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    使用underline.js或lo dash,可以执行以下操作:

    _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
    => [1, 2, 3, 101, 10]
    

    http://underscorejs.org/#union

    http://lodash.com/docs#union

        3
  •  220
  •   simo    11 年前

    首先连接两个数组,然后只筛选出唯一的项。

    var a = [1, 2, 3], b = [101, 2, 1, 10];
    var c = a.concat(b);
    var d = c.filter(function (item, pos) {return c.indexOf(item) == pos});
    
    // d is [1,2,3,101,10]
    

    http://jsfiddle.net/simo/98622/

    编辑

    正如@dmitry建议的(请参阅下面的第二条注释),更明智的解决方案是筛选出 b 在与连接之前 a

    var a = [1, 2, 3], b = [101, 2, 1, 10];
    var c = a.concat(b.filter(function (item) {
        return a.indexOf(item) < 0;
    }));
    
    // d is [1,2,3,101,10]
    
        4
  •  140
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    这是一个ECMAScript 6解决方案,使用 spread operator 和数组泛型。

    目前它只适用于火狐,也可能是Internet Explorer技术预览版。

    但是如果你使用 Babel ,你现在可以吃了。

    // Input: [ [1, 2, 3], [101, 2, 1, 10], [2, 1] ]
    // Output: [1, 2, 3, 101, 10]
    function mergeDedupe(arr)
    {
      return [...new Set([].concat(...arr))];
    }
    
        5
  •  113
  •   Abdennour TOUMI    9 年前

    ES6

    array1.push(...array2) // => don't remove duplication 
    

    [...array1,...array2] //   =>  don't remove duplication 
    

    [...new Set([...array1 ,...array2])]; //   => remove duplication
    
        6
  •  46
  •   Benny Code    8 年前

    使用A Set (ECMAScript 2015),简单如下:

    const array1 = ["Vijendra", "Singh"];
    const array2 = ["Singh", "Shakya"];
    const array3 = Array.from(new Set(array1.concat(array2)));
    
        7
  •  33
  •   Brak    7 年前

    这里是一个稍微不同的环。利用最新版本的chrome中的一些优化,它是解决两个数组联合的最快方法(chrome 38.0.2111)。

    http://jsperf.com/merge-two-arrays-keeping-only-unique-values

    var array1 = ["Vijendra", "Singh"];
    var array2 = ["Singh", "Shakya"];
    var array3 = [];
    
    var arr = array1.concat(array2),
      len = arr.length;
    
    while (len--) {
      var itm = arr[len];
      if (array3.indexOf(itm) === -1) {
        array3.unshift(itm);
      }
    }
    

    while循环:~589k次/秒
    过滤器:~445k ops/s
    洛达什:308k ops/s
    对于回路:225k ops/s

    一条评论指出,我的一个设置变量导致我的循环领先于其他变量,因为它不需要初始化一个空数组来写入。我同意这一点,所以我重写了测试,甚至在比赛场地,并包括一个更快的选择。

    http://jsperf.com/merge-two-arrays-keeping-only-unique-values/52

    let whileLoopAlt = function (array1, array2) {
        const array3 = array1.slice(0);
        let len1 = array1.length;
        let len2 = array2.length;
        const assoc = {};
    
        while (len1--) {
            assoc[array1[len1]] = null;
        }
    
        while (len2--) {
            let itm = array2[len2];
    
            if (assoc[itm] === undefined) { // Eliminate the indexOf call
                array3.push(itm);
                assoc[itm] = null;
            }
        }
    
        return array3;
    };
    

    在这个替代解决方案中,我结合了一个答案的关联数组解决方案来消除 .indexOf() 在第二个循环中调用这个循环大大降低了速度,并包含了其他用户在他们的答案中建议的一些其他优化。

    在这里,每个值(i-1)上的双循环的最高答案仍然明显较慢。罗达什仍然做得很好,我仍然会向任何不介意在他们的项目中添加图书馆的人推荐它。对于那些不想这样做的人来说,我的while循环仍然是一个很好的答案,过滤器的答案在这里有一个很强的显示,在我的测试中用最新的淡黄色(44.0.2360)打败了所有人。

    退房 Mike's answer Dan Stocker's answer 如果你想加快速度。在浏览了几乎所有可行的答案之后,这些都是迄今为止所有结果中最快的。

        8
  •  31
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    你只需使用ecmascript 6,

    var array1 = ["Vijendra", "Singh"];
    var array2 = ["Singh", "Shakya"];
    var array3 = [...new Set([...array1 ,...array2])];
    console.log(array3); // ["Vijendra", "Singh", "Shakya"];
    
    • 使用 spread operator 用于连接数组。
    • 使用 Set 用于创建一组不同的元素。
    • 再次使用Spread运算符将集合转换为数组。
        9
  •  16
  •   GAgnew    14 年前
    Array.prototype.merge = function(/* variable number of arrays */){
        for(var i = 0; i < arguments.length; i++){
            var array = arguments[i];
            for(var j = 0; j < array.length; j++){
                if(this.indexOf(array[j]) === -1) {
                    this.push(array[j]);
                }
            }
        }
        return this;
    };
    

    更好的数组合并函数。

        10
  •  15
  •   Benjamin Gakami    7 年前

    合并两个数组并删除ES6中的重复项

    let arr1 = [3, 5, 2, 2, 5, 5];
    let arr2 = [2, 1, 66, 5];
    let unique = [...new Set([...arr1,...arr2])];
    console.log(unique);
    // [ 3, 5, 2, 1, 66 ]
    
        11
  •  14
  •   Mike    13 年前

    就把我的两分钱投进去。

    function mergeStringArrays(a, b){
        var hash = {};
        var ret = [];
    
        for(var i=0; i < a.length; i++){
            var e = a[i];
            if (!hash[e]){
                hash[e] = true;
                ret.push(e);
            }
        }
    
        for(var i=0; i < b.length; i++){
            var e = b[i];
            if (!hash[e]){
                hash[e] = true;
                ret.push(e);
            }
        }
    
        return ret;
    }
    

    这是一个我经常使用的方法,它使用一个对象作为哈希查找表来进行重复检查。假设散列是O(1),那么它在O(n)中运行,其中n是a.length+b.length。老实说,我不知道浏览器是如何处理散列的,但是它在数千个数据点上运行得很好。

        12
  •  14
  •   Dan Stocker    11 年前

    只需避开嵌套循环(o(n^2)),以及 .indexOf() (+O(n))。

    function merge(a, b) {
        var hash = {}, i;
        for (i=0; i<a.length; i++) {
            hash[a[i]]=true;
        } 
        for (i=0; i<b.length; i++) {
            hash[b[i]]=true;
        } 
        return Object.keys(hash);
    }
    
        13
  •  13
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    你为什么不用物体?看起来你在模拟一个场景。然而,这并不能维持秩序。

    var set1 = {"Vijendra":true, "Singh":true}
    var set2 = {"Singh":true,  "Shakya":true}
    
    // Merge second object into first
    function merge(set1, set2){
      for (var key in set2){
        if (set2.hasOwnProperty(key))
          set1[key] = set2[key]
      }
      return set1
    }
    
    merge(set1, set2)
    
    // Create set from array
    function setify(array){
      var result = {}
      for (var item in array){
        if (array.hasOwnProperty(item))
          result[array[item]] = true
      }
      return result
    }
    
        14
  •  8
  •   Hero Qu    10 年前

    我的一个半便士:

    Array.prototype.concat_n_dedupe = function(other_array) {
      return this
        .concat(other_array) // add second
        .reduce(function(uniques, item) { // dedupe all
          if (uniques.indexOf(item) == -1) {
            uniques.push(item);
          }
          return uniques;
        }, []);
    };
    
    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    
    var result = array1.concat_n_dedupe(array2);
    
    console.log(result);
    
        15
  •  8
  •   Andrew    8 年前

    简化 simo's answer 把它变成了一个很好的功能。

    function mergeUnique(arr1, arr2){
        return arr1.concat(arr2.filter(function (item) {
            return arr1.indexOf(item) === -1;
        }));
    }
    
        16
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    最佳解决方案…

    您可以直接在浏览器控制台中点击…

    无副本

    a = [1, 2, 3];
    b = [3, 2, 1, "prince"];
    
    a.concat(b.filter(function(el) {
        return a.indexOf(el) === -1;
    }));
    

    带副本

    ["prince", "asish", 5].concat(["ravi", 4])
    

    如果你不想重复,你可以从这里尝试一个更好的解决方案。- Shouting Code .

    [1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
        return [1, 2, 3].indexOf(el) === -1;
    }));
    

    试用Chrome浏览器控制台

     f12 > console
    

    输出:

    ["prince", "asish", 5, "ravi", 4]
    
    [1, 2, 3, "prince"]
    
        17
  •  6
  •   Amarghosh    16 年前
    //Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
    //We need to implement it explicitly for other browsers, 
    if (!Array.prototype.indexOf)
    {
      Array.prototype.indexOf = function(elt, from)
      {
        var len = this.length >>> 0;
    
        for (; from < len; from++)
        {
          if (from in this &&
              this[from] === elt)
            return from;
        }
        return -1;
      };
    }
    //now, on to the problem
    
    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    
    var merged = array1.concat(array2);
    var t;
    for(i = 0; i < merged.length; i++)
      if((t = merged.indexOf(i + 1, merged[i])) != -1)
      {
        merged.splice(t, 1);
        i--;//in case of multiple occurrences
      }
    

    执行 indexOf 其他浏览器的方法来自 MDC

        18
  •  6
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    您只需使用underline.js的=> UNIQ :

    array3 = _.uniq(array1.concat(array2))
    
    console.log(array3)
    

    它会打印出来 [“Vijendra”、“Singh”、“Shakya”] .

        19
  •  6
  •   Sarfaraaz Kirschstein    8 年前

    它可以用set来完成。

    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    
    var array3 = array1.concat(array2);
    var tempSet = new Set(array3);
    array3 = Array.from(tempSet);
    
    //show output
    document.body.querySelector("div").innerHTML = JSON.stringify(array3);
    <div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" > 
      temp text 
    </div>
        20
  •  5
  •   meder omuraliev    16 年前

    新解决方案(使用 Array.prototype.indexOf Array.prototype.concat )以下内容:

    Array.prototype.uniqueMerge = function( a ) {
        for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
            if ( this.indexOf( a[i] ) === -1 ) {
                nonDuplicates.push( a[i] );
            }
        }
        return this.concat( nonDuplicates )
    };
    

    用途:

    >>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
    ["Vijendra", "Singh", "Shakya"]
    

    array.prototype.indexof(用于Internet Explorer):

    Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
      {
        var len = this.length >>> 0;
    
        var from = Number(arguments[1]) || 0;
        from = (from < 0) ? Math.ceil(from): Math.floor(from); 
        if (from < 0)from += len;
    
        for (; from < len; from++)
        {
          if (from in this && this[from] === elt)return from;
        }
        return -1;
      };
    
        21
  •  5
  •   Lajos Mészáros Noctisdark    13 年前
    Array.prototype.add = function(b){
        var a = this.concat();                // clone current object
        if(!b.push || !b.length) return a;    // if b is not an array, or empty, then return a unchanged
        if(!a.length) return b.concat();      // if original is empty, return b
    
        // go through all the elements of b
        for(var i = 0; i < b.length; i++){
            // if b's value is not in a, then add it
            if(a.indexOf(b[i]) == -1) a.push(b[i]);
        }
        return a;
    }
    
    // Example:
    console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]
    
        22
  •  5
  •   SuperDJ Franklin Rivero    8 年前
    array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
    

    这个方法的好处在于性能,一般来说,在处理数组时,您都是链接方法,如过滤器、映射等,因此您可以添加该行,它将使用array1连接并消除array2的重复数据,而不需要引用后面的方法(当您没有链接方法时),例如:

    someSource()
    .reduce(...)
    .filter(...)
    .map(...) 
    // and now you want to concat array2 and deduplicate:
    .concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
    // and keep chaining stuff
    .map(...)
    .find(...)
    // etc
    

    (我不想污染array.prototype,这是尊重这个链的唯一方法——定义一个新的函数会破坏它——所以我认为只有这样才能实现这个目标)

        23
  •  4
  •   user1079877    7 年前

    对于ES6,只需一行:

    a = [1, 2, 3, 4]
    b = [4, 5]
    [...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]
    
        24
  •  3
  •   Mark Tyers    8 年前

    为了这个…下面是一个单行解决方案:

    const x = [...new Set([['C', 'B'],['B', 'A']].reduce( (a, e) => a.concat(e), []))].sort()
    // ['A', 'B', 'C']
    

    不太可读,但可能有助于:

    1. 将初始累加器值设置为空数组的reduce函数应用。
    2. reduce函数使用concat将每个子数组附加到累加器数组中。
    3. 将此结果作为构造函数参数传递,以创建新的 Set .
    4. Spread运算符用于转换 集合 一个数组。
    5. 这个 sort() 函数应用于新数组。
        25
  •  3
  •   Bharti Ladumor    7 年前
    var arr1 = [1, 3, 5, 6];
    var arr2 = [3, 6, 10, 11, 12];
    arr1.concat(arr2.filter(ele => !arr1.includes(ele)));
    console.log(arr1);
    
    output :- [1, 3, 5, 6, 10, 11, 12]
    
        26
  •  2
  •   Richard Ayotte    14 年前

    在Dojo 1.6 +

    var unique = []; 
    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    var array3 = array1.concat(array2); // Merged both arrays
    
    dojo.forEach(array3, function(item) {
        if (dojo.indexOf(unique, item) > -1) return;
        unique.push(item); 
    });
    

    更新

    请参见工作代码。

    http://jsfiddle.net/UAxJa/1/

        27
  •  2
  •   TxRegex    12 年前

    合并无限数量的数组或非数组并保持其唯一性:

    function flatMerge() {
        return Array.prototype.reduce.call(arguments, function (result, current) {
            if (!(current instanceof Array)) {
                if (result.indexOf(current) === -1) {
                    result.push(current);
                }
            } else {
                current.forEach(function (value) {
                    console.log(value);
                    if (result.indexOf(value) === -1) {
                        result.push(value);
                    }
                });
            }
            return result;
        }, []);
    }
    
    flatMerge([1,2,3], 4, 4, [3, 2, 1, 5], [7, 6, 8, 9], 5, [4], 2, [3, 2, 5]);
    // [1, 2, 3, 4, 5, 7, 6, 8, 9]
    
    flatMerge([1,2,3], [3, 2, 1, 5], [7, 6, 8, 9]);
    // [1, 2, 3, 5, 7, 6, 8, 9]
    
    flatMerge(1, 3, 5, 7);
    // [1, 3, 5, 7]
    
        28
  •  2
  •   Billy Moon    10 年前

    假设原始数组不需要重复数据消除,这应该非常快,保持原始顺序,并且不修改原始数组…

    function arrayMerge(base, addendum){
        var out = [].concat(base);
        for(var i=0,len=addendum.length;i<len;i++){
            if(base.indexOf(addendum[i])<0){
                out.push(addendum[i]);
            }
        }
        return out;
    }
    

    用途:

    var array1 = ["Vijendra","Singh"];
    var array2 = ["Singh", "Shakya"];
    var array3 = arrayMerge(array1, array2);
    
    console.log(array3);
    //-> [ 'Vijendra', 'Singh', 'Shakya' ]
    
        29
  •  2
  •   user6445533    9 年前

    ES2015的功能方法

    遵循功能方法A union 两个 Array S只是 concat filter . 为了提供最佳性能,我们求助于本地 Set 为属性查找优化的数据类型。

    总之,关键问题与 联盟 函数是如何处理重复项。以下排列是可能的:

    Array A      + Array B
    
    [unique]     + [unique]
    [duplicated] + [unique]
    [unique]     + [duplicated]
    [duplicated] + [duplicated]
    

    前两个排列很容易用一个函数处理。然而,最后两个更复杂,因为你不能处理它们只要你依赖 集合 查找。从切换到普通老 Object 属性查找将导致严重的性能损失。下面的实现忽略了第三和第四排列。你必须建立一个单独的版本 联盟 支持他们。


    // small, reusable auxiliary functions
    
    const comp = f => g => x => f(g(x));
    const apply = f => a => f(a);
    const flip = f => b => a => f(a) (b);
    const concat = xs => y => xs.concat(y);
    const afrom = apply(Array.from);
    const createSet = xs => new Set(xs);
    const filter = f => xs => xs.filter(apply(f));
    
    
    // de-duplication
    
    const dedupe = comp(afrom) (createSet);
    
    
    // the actual union function
    
    const union = xs => ys => {
      const zs = createSet(xs);  
      return concat(xs) (
        filter(x => zs.has(x)
         ? false
         : zs.add(x)
      ) (ys));
    }
    
    
    // mock data
    
    const xs = [1,2,2,3,4,5];
    const ys = [0,1,2,3,3,4,5,6,6];
    
    
    // here we go
    
    console.log( "unique/unique", union(dedupe(xs)) (ys) );
    console.log( "duplicated/unique", union(xs) (ys) );

    从这里开始,实现 unionn 函数,它接受任意数量的数组(受naomik的注释启发):

    // small, reusable auxiliary functions
    
    const uncurry = f => (a, b) => f(a) (b);
    const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);
    
    const apply = f => a => f(a);
    const flip = f => b => a => f(a) (b);
    const concat = xs => y => xs.concat(y);
    const createSet = xs => new Set(xs);
    const filter = f => xs => xs.filter(apply(f));
    
    
    // union and unionn
    
    const union = xs => ys => {
      const zs = createSet(xs);  
      return concat(xs) (
        filter(x => zs.has(x)
         ? false
         : zs.add(x)
      ) (ys));
    }
    
    const unionn = (head, ...tail) => foldl(union) (head) (tail);
    
    
    // mock data
    
    const xs = [1,2,2,3,4,5];
    const ys = [0,1,2,3,3,4,5,6,6];
    const zs = [0,1,2,3,4,5,6,7,8,9];
    
    
    // here we go
    
    console.log( unionn(xs, ys, zs) );

    结果证明 联合国 只是 foldl (阿卡 Array.prototype.reduce ,这需要 联盟 作为它的减速器。注意:由于实现不使用额外的累加器,因此在没有参数的情况下应用它时,它将抛出一个错误。

        30
  •  2
  •   Stelios Voskos    9 年前

    最简单的方法是使用 concat() 合并数组,然后使用 filter() 删除重复项,或使用 连接() 然后将合并的数组放入 Set() .

    第一种方式:

    const firstArray = [1,2, 2];
    const secondArray = [3,4];
    // now lets merge them
    const mergedArray = firstArray.concat(secondArray); // [1,2,2,3,4]
    //now use filter to remove dups
    const removeDuplicates = mergedArray.filter((elem, index) =>  mergedArray.indexOf(elem) === index); // [1,2,3, 4]
    

    第二种方法(但对用户界面有性能影响):

    const firstArray = [1,2, 2];
    const secondArray = [3,4];
    // now lets merge them
    const mergedArray = firstArray.concat(secondArray); // [1,2,2,3,4]
    const removeDuplicates = new Set(mergedArray);