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

IT技术 javascript arrays merge
2020-12-12 16:18:49

我有两个 JavaScript 数组:

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

我希望输出是:

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

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

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

6个回答

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

ES5 版本使用Array.concat

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

console.log(array1.concat(array2));

ES6 版本使用解构

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.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;
    }
});
我最初对此投了赞成票,但改变了主意。将原型分配给 Array.prototype 会破坏“for ... in”语句。所以最好的解决方案可能是使用这样的函数,但不要将其指定为原型。有些人可能会争辩说,无论如何都不应该使用“for ... in”语句来迭代数组元素,但人们经常以这种方式使用它们,因此至少要谨慎使用此解决方案。
2021-02-14 16:18:49
你应该总是使用for ... inwithhasOwnProperty在这种情况下原型方法很好
2021-02-16 16:18:49
只需使用 Babel 并Set()如另一个答案中所述。
2021-02-16 16:18:49
请注意,此算法为 O(n^2)。
2021-02-20 16:18:49
[a, b, c][x, b, d]成为数组(假设引号)。concat 给出[a, b, c, x, b, d]. unique() 的输出不会是[a, c, x, b, d]. 这不会保留我认为的顺序 - 我相信 OP 想要[a, b, c, x, d]
2021-03-01 16:18:49

使用 Underscore.js 或 Lo-Dash,您可以:

console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

http://underscorejs.org/#union

http://lodash.com/docs#union

我更喜欢 underscore.js。我最终使用的是underscore.flatten(),它比 union 更好,因为它需要一组数组。
2021-02-10 16:18:49
lodash 与最佳答案的快速性能对比:jsperf.com/merge-two-arrays-keeping-only-unique-values
2021-02-11 16:18:49
@Ygg 来自 lodash 文档。按顺序返回一个新的唯一值数组,这些值存在于一个或多个数组中。”
2021-02-13 16:18:49
@weaver _.flatten 合并,但不“去重”。
2021-02-13 16:18:49
或者,甚至比下划线更好的是 API 兼容的lodash
2021-02-21 16:18:49

首先连接两个数组,然后仅过滤掉唯一项:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b)
var d = c.filter((item, pos) => c.indexOf(item) === pos)

console.log(d) // d is [1, 2, 3, 101, 10]

编辑

正如所建议的那样,一个更明智的解决方案是在b与 连接之前过滤掉独特的项目a

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b.filter((item) => a.indexOf(item) < 0))

console.log(c) // c is [1, 2, 3, 101, 10]

@Andrew:更好:1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])];
2021-02-08 16:18:49
这里的原始解决方案具有删除每个源阵列中的重复项的好处。我想这取决于您将使用的上下文。
2021-02-12 16:18:49
如果我想实际更改a为 add b,那么循环并使用 push 会更好吗?a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
2021-02-23 16:18:49
只是提醒人们对 IE6 感到焦虑的当前浏览器使用情况caniuse.com/usage-table
2021-03-03 16:18:49
您可以为 IE6 支持合并不同的: c = Array.from(new Set(c));
2021-03-06 16:18:49
[...array1,...array2] //   =>  don't remove duplication 

或者

[...new Set([...array1 ,...array2])]; //   => remove duplication
应该被接受为现代 Javascript 的答案。
2021-02-14 16:18:49
不适用于对象数组,因为它只会合并对象引用,而不关心对象本身是否相等。
2021-02-19 16:18:49
那么你会怎么做呢?
2021-02-23 16:18:49
请注意,除非它们是相同的对象引用,否则 for set 不能对具有相同键值对的两个对象进行重复数据删除。
2021-03-03 16:18:49
第一个/第二个示例根本没有union+ 第一个示例炸毁大Arrays的堆栈+ 第三个示例非常慢并且消耗大量内存,因为Array必须构建两个中间s + 第三个示例只能用于union已知Array编译时s
2021-03-06 16:18:49

这是一个使用扩展运算符和数组泛型的 ECMAScript 6 解决方案

目前它只适用于 Firefox,可能也适用于 Internet Explorer Technical Preview。

但是如果你使用Babel,你现在就可以拥有它。

const input = [
  [1, 2, 3],
  [101, 2, 1, 10],
  [2, 1]
];
const mergeDedupe = (arr) => {
  return [...new Set([].concat(...arr))];
}

console.log('output', mergeDedupe(input));

很难说这应该是公认的答案,因为问题来自 2009 年。但是,是的,这不仅更“高效”而且“优雅”
2021-02-12 16:18:49
这是非常优雅的。不幸的是,Typescript 还不支持这个。stackoverflow.com/questions/33464504/...
2021-02-16 16:18:49
这应该添加到已接受的答案中。这个解决方案比目前可能的解决方案更高效、更优雅,但这是我们不可避免地能够做的(并且应该做以跟上该领域的步伐)。
2021-02-22 16:18:49
Array.from 可以用来代替扩展运算符: Array.from(new Set([].concat(...arr)))
2021-02-22 16:18:49
这与 OP 的问题并不完全相同(这似乎更像是一个平面地图而不是任何东西),但要投票,因为它很棒。
2021-02-25 16:18:49