首页 文章

如何在JavaScript中合并两个数组并重复删除项目

提问于
浏览
1050

我有两个JavaScript数组:

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

我希望输出为:

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

输出数组应该删除重复的单词 .

如何在JavaScript中合并两个数组,以便我只按照它们插入原始数组的相同顺序获取每个数组中的唯一项?

30 回答

  • 5

    我的一分半便士:

    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);
    
  • 2
    array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
    

    关于这个的好处是性能,你通常在使用数组时会链接像filter,map等方法,所以你可以添加该行,它将使用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,这将是尊重链的唯一方式 - 定义一个新函数会破坏它 - 所以我认为这样的事情是唯一的方法来实现)

  • 6
    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]
    
  • 4

    你可以使用Underscore.js => uniq 来实现它:

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

    它将打印 ["Vijendra", "Singh", "Shakya"] .

  • 209

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

    Update

    查看工作代码 .

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

  • 5

    这是使用spread operator和数组泛型的ECMAScript 6解决方案 .

    目前它只适用于Firefox,可能还适用于Internet Explorer Technical Preview .

    但是如果你使用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

    你为什么不用一个物体?看起来你正试图模拟一套 . 但是,这不会保留订单 .

    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
    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]
    
  • 1319

    最简单的方法是使用 concat() 合并数组,然后使用 filter() 删除重复项,或者使用 concat() 然后将合并后的数组放在 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]
    

    第二种方式(但在UI上具有性能影响):

    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);
    
  • 2

    你可以用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运算符将Set转换为数组 .

  • 3

    只需避开嵌套循环(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);
    }
    
  • 8

    刚扔掉我的两分钱 .

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

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

  • 5

    使用Underscore.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

  • 13

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

    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所建议的那样(参见下面的第二条评论),更明智的解决方案是在与 a 连接之前过滤出 b 中的唯一项目

    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]
    
  • 2

    ES6

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

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

    [...new Set([...array1 ,...array2])]; //   => remove duplication
    
  • 13

    假设原始数组不需要重复数据删除,这应该非常快,保留原始顺序,并且不会修改原始数组...

    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' ]
    
  • 7

    为了它...这是一个单行解决方案:

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

    不是特别可读,但它可以帮助某人:

    • 应用reduce函数,并将初始累加器值设置为空数组 .

    • reduce函数使用concat将每个子数组附加到累加器数组 .

    • 结果作为构造函数参数传递,以创建新的 Set .

    • 扩展运算符用于将 Set 转换为数组 .

    • sort() 函数应用于新数组 .

  • 37

    ES2015的功能方法

    在功能方法之后,两个 Arrayunion 只是 concatfilter 的组成 . 为了提供最佳性能,我们采用了原生的 Set 数据类型,该类型针对属性查找进行了优化 .

    无论如何,与 union 函数结合的关键问题是如何处理重复项 . 以下排列是可能的:

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

    前两个排列很容易用单一功能处理 . 但是,最后两个更复杂,因为只要依赖 Set 查找,就无法处理它们 . 由于切换到普通的旧式 Object 属性查找会导致严重的性能损失,因此以下实现只忽略第三和第四个排列 . 您必须构建一个单独的 union 版本才能支持它们 .


    // 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) );
    

    事实证明 unionn 只是 foldl (又名 Array.prototype.reduce ),它以 union 为减速器 . 注意:由于实现不使用额外的累加器,因此在不使用参数的情况下应用它时会抛出错误 .

  • 6

    这是一个稍微不同的循环 . 通过最新版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 ops / s
    过滤器:~445k ops / s
    lodash:308k ops / s
    for循环:225k ops / s

    注释指出我的一个设置变量导致我的循环领先于其余变量,因为它不必初始化要写入的空数组 . 我同意这一点,所以我已经将测试改写为公平竞争,并且包括更快的选项 .

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

    var whileLoopAlt = function(array1, array2) {
        var array3 = [];
        var arr = array1.concat(array2);
        var len = arr.length;
        var assoc = {};
    
        while(len--) {
            var itm = arr[len];
    
            if(!assoc[itm]) { // Eliminate the indexOf call
                array3.unshift(itm);
                assoc[itm] = true;
            }
        }
    
        return array3;
    };
    

    在这个替代解决方案中,我用've combined one answer' s关联数组解决方案来消除循环中的 .indexOf() 调用使用第二个循环减慢了很多事情,并包括其他用户在其答案中建议的一些其他优化 .

    这里的最佳答案是每个值(i-1)上的双循环仍然明显变慢 . lodash仍然很强大,我还是会推荐给那些不介意在他们的项目中添加库的人 . 对于那些不想要的人来说,我的while循环仍然是一个很好的答案,过滤器的答案在这里有很强的表现,在撰写本文时,最新的Canary Chrome(44.0.2360)测试结果一目了然 .

    如果你想提高速度,请查看Mike's answerDan Stocker's answer . 在经历了几乎所有可行的答案之后,这些是迄今为止所有结果中最快的 .

  • 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版本使用解构

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

    由于没有'built in'方法来删除重复项(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.prototypefor 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;
        }
    });
    
  • 14

    简化simo's answer并将其转换为一个很好的功能 .

    function mergeUnique(arr1, arr2){
        return arr1.concat(arr2.filter(function (item) {
            return arr1.indexOf(item) === -1;
        }));
    }
    
  • 522

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

    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]
    
  • 128
    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;
    };
    

    一个更好的阵列合并功能 .

  • 31
    //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

  • 29

    对于ES6,只需一行:

    a = [1, 2, 3, 4]
    b = [4, 5]
    [...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]
    
  • 7

    新解决方案(使用 Array.prototype.indexOfArray.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;
      };
    
  • 2

    它可以使用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>
    
  • 2

    最好的解决方案......

    您可以通过点击直接在浏览器控制台中查看...

    没有重复

    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"]
    
  • 108

    使用Set(ECMAScript 2015),它将如此简单:

    const array1 = ["Vijendra", "Singh"];
    const array2 = ["Singh", "Shakya"];
    const array3 = Array.from(new Set(array1.concat(array2)));
    
  • 3

    合并两个数组并删除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 ]
    

相关问题