在JavaScript中获得两个数组的联合[重复]

Posted

技术标签:

【中文标题】在JavaScript中获得两个数组的联合[重复]【英文标题】:Getting a union of two arrays in JavaScript [duplicate] 【发布时间】:2011-04-07 11:41:15 【问题描述】:

假设我有一个[34, 35, 45, 48, 49] 数组和另一个[48, 55] 数组。如何获得[34, 35, 45, 48, 49, 55] 的结果数组?

【问题讨论】:

有了 ES6 的好东西,它将只是一个没有依赖关系的单行器。遗憾的是,我们需要等待很长时间才能在所有现代浏览器中使用它。无论如何,请检查my answer This 在 Code Golf 中的实现是 IMO 最优雅、最高效的解决方案。 【参考方案1】:

随着带有集合和 splat 运算符的 ES6 的到来(当时仅在 Firefox 中有效,请检查兼容性表),您可以编写以下神秘的一行:

var a = [34, 35, 45, 48, 49];
var b = [48, 55];
var union = [...new Set([...a, ...b])];
console.log(union);

关于这一行的一点解释:[...a, ...b] 连接两个数组,你也可以使用a.concat(b)new Set() 用它创建一个集合,从而创建你的联盟。最后一个[...x] 将其转换回数组。

【讨论】:

性能怎么样 @RPallas 我没有进行任何测试(您可以在这里轻松地进行测试jsperf.com)。但是这里的所有功能都是原生的,这表明它应该比任何非原生的更快。 这里的性能测试:jsperf.com/union-speeds/1 它比 lodash 解决方案慢一点,但除非您实时执行大量大型联合,否则不太重要。如果是这样的话,你可能应该研究一个更快的解决方案,比如 Lazy.js Typescript 在抱怨,我用 Array.from(new Set([...a, ...b])) 替换了扩展运算符,它起作用了。【参考方案2】:

如果您不需要保留订单,并认为45"45" 相同:

function union_arrays (x, y) 
  var obj = ;
  for (var i = x.length-1; i >= 0; -- i)
     obj[x[i]] = x[i];
  for (var i = y.length-1; i >= 0; -- i)
     obj[y[i]] = y[i];
  var res = []
  for (var k in obj) 
    if (obj.hasOwnProperty(k))  // <-- optional
      res.push(obj[k]);
  
  return res;


console.log(union_arrays([34,35,45,48,49], [44,55]));

【讨论】:

不关心订单。这工作得很好。谢谢 这对于对象数组将失败。 union_arrays([a:1], [b:2]) 将返回 [b:2]。 为什么不跳过声明 res 和整个“for(var k in obj)... push...”而只返回 Object.keys(obj)?您还可以使用“var both = x.concat(y)”将这两个初始 for 循环合并为一个,以将两个数组连接为一个。这样,您也可以合并任意数量的数组。 @Jemenake Object.keys() 在 2010 年不存在。 也许i &gt;= 0 可以代替i【参考方案3】:

如果你使用库 underscore 你可以这样写

var unionArr = _.union([34,35,45,48,49], [48,55]);
console.log(unionArr);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"&gt;&lt;/script&gt;

参考:http://underscorejs.org/#union

【讨论】:

我通常不会为一小部分功能引用一个全新的库,但是下划线库有很多非常有用的函数来处理数组。我也最终使用了 _.intersection 和 _.without 函数。 Lodash 还有一个great implementation for union【参考方案4】:

我可能在这里浪费时间在一个死线程上。我只需要实现这一点,然后去看看我是否在浪费时间。

我真的很喜欢 KennyTM 的回答。这就是我要解决的问题。将密钥合并到哈希中以自然消除重复项,然后提取密钥。如果你真的有 jQuery,你可以利用它的好东西把它变成一个 2 行问题,然后把它放到一个扩展中。 jQuery 中的 each() 将负责不遍历 hasOwnProperty() 为 false 的项目。

jQuery.fn.extend(
    union: function(array1, array2) 
        var hash = , union = [];
        $.each($.merge($.merge([], array1), array2), function (index, value)  hash[value] = value; );
        $.each(hash, function (key, value)  union.push(key);  );
        return union;
    
);

请注意,两个原始数组都保持不变。然后你这样称呼它:

var union = $.union(array1, array2);

【讨论】:

我认为这是最好的答案,因为这个函数似乎在 O(2n) 中工作(由于两个非嵌套的 for 循环而更快),而不是其余的似乎在O(n^2)(慢)时尚。 恒杰,真的是O(2n)吗?我认为,$.merge 有 O(n) 甚至 O(n*n) 而不是 O(1)。如果单独填充哈希而不合并,这可以优化到 O(3n) @Hengjie: Kenny 的答案是 O(3n) O(n) == O(2n) == O(3n)【参考方案5】:

function unique(arrayName)

  var newArray=new Array();
  label: for(var i=0; i<arrayName.length;i++ )
    
    for(var j=0; j<newArray.length;j++ )
    
      if(newArray[j]==arrayName[i]) 
        continue label;
    
    newArray[newArray.length] = arrayName[i];
  
  return newArray;


var arr1 = new Array(0,2,4,4,4,4,4,5,5,6,6,6,7,7,8,9,5,1,2,3,0);
var arr2= new Array(3,5,8,1,2,32,1,2,1,2,4,7,8,9,1,2,1,2,3,4,5);
var union = unique(arr1.concat(arr2));
console.log(union);

【讨论】:

也许我只是感到困惑,但这将如何运作?你正在传递 arr3,但没有 arr3,即使有它看起来也不像是 arr1 上的联合 | arr2 像他要求的那样? 我很困惑这怎么行不通? @Angelo R.:你说得对:“没有 arr3。” var arr2 = []; if (currTaskIDs != '') if( $.inArray(currTaskIDs, arr2) == -1) arr2.push(currTaskIDs); arr2 = 独特的(arr2.concat(arr));现在,currTaskIDs = 34,35,45,48,49 如果我选择说 50,它会删除所有这些并只显示 50 顺便说一句,如果我只是使用这个: var currTaskIDs = $("#taskIDList").val(); // 开始:创建任务列表: if (currTaskIDs != '') if( $.inArray(currTaskIDs, arr) == -1) arr.push(currTaskIDs); arr = 独特的(arr);它第一次完美运行。如果我向我的 currTaskIDs 添加另一个值,那么它会变成:34,35,45,48,49,50,34,35,45,48,49,50,38【参考方案6】:

如果你想连接两个没有重复值的数组,试试这个

var a=[34, 35, 45, 48, 49];
var b=[48, 55];
var c=a.concat(b).sort();
var res=c.filter((value,pos) => return c.indexOf(value) == pos; );

【讨论】:

好主意,但它改变了订单的项目。 去掉排序方法就可以解决你的问题 不错!或者如果您已经在方法链接中(您没有对 c 的引用)的变体:``` [1,2,3].concat([2,3,4]) .filter((value, pos, arr)=>arr.indexOf(value)===pos)```【参考方案7】:

改编自:https://***.com/a/4026828/1830259

Array.prototype.union = function(a) 

    var r = this.slice(0);
    a.forEach(function(i)  if (r.indexOf(i) < 0) r.push(i); );
    return r;
;

Array.prototype.diff = function(a)

    return this.filter(function(i) return a.indexOf(i) < 0;);
;

var s1 = [1, 2, 3, 4];
var s2 = [3, 4, 5, 6];

console.log("s1: " + s1);
console.log("s2: " + s2);
console.log("s1.union(s2): " + s1.union(s2));
console.log("s2.union(s1): " + s2.union(s1));
console.log("s1.diff(s2): " + s1.diff(s2));
console.log("s2.diff(s1): " + s2.diff(s1));

// Output:
// s1: 1,2,3,4
// s2: 3,4,5,6
// s1.union(s2): 1,2,3,4,5,6
// s2.union(s1): 3,4,5,6,1,2
// s1.diff(s2): 1,2
// s2.diff(s1): 5,6 

【讨论】:

【参考方案8】:

我喜欢 Peter Ajtai 的 concat-then-unique 解决方案,但代码不是很清楚。这是一个更好的选择:

function unique(x) 
  return x.filter(function(elem, index)  return x.indexOf(elem) === index; );
;
function union(x, y) 
  return unique(x.concat(y));
;

由于 indexOf 返回第 次出现的索引,我们将其与当前元素的索引(过滤谓词的第二个参数)进行检查。

【讨论】:

【参考方案9】:

您可以使用 jQuery 插件:jQuery Array Utilities

例如下面的代码

$.union([1, 2, 2, 3], [2, 3, 4, 5, 5])

将返回 [1,2,3,4,5]

【讨论】:

这个联合函数还支持任意数量的数组,这个包jquery-array-utilities也可以使用bower安装。我想添加一个我最初制作插件的免责声明 :)【参考方案10】:

kennytm 回答的简短版本:

function unionArrays(a, b) 
    const cache = ;

    a.forEach(item => cache[item] = item);
    b.forEach(item => cache[item] = item);

    return Object.keys(cache).map(key => cache[key]);
;

【讨论】:

【参考方案11】:
function unite(arr1, arr2, arr3) 
 newArr=arr1.concat(arr2).concat(arr3);

 a=newArr.filter(function(value)
   return !arr1.some(function(value2)
      return value == value2;
   );
 );

console.log(arr1.concat(a));

//This is for Sorted union following the order :)

【讨论】:

【参考方案12】:

function unionArrays() 
    var args = arguments,
    l = args.length,
    obj = ,
    res = [],
    i, j, k;

    while (l--) 
        k = args[l];
        i = k.length;

        while (i--) 
            j = k[i];
            if (!obj[j]) 
                obj[j] = 1;
                res.push(j);
            
           
    

    return res;

var unionArr = unionArrays([34, 35, 45, 48, 49], [44, 55]);
console.log(unionArr);

在方法上与 alejandro 的方法有些相似,但要短一些,并且应该适用于任意数量的数组。

【讨论】:

【参考方案13】:

function unionArray(arrayA, arrayB) 
  var obj = ,
      i = arrayA.length,
      j = arrayB.length,
      newArray = [];
  while (i--) 
    if (!(arrayA[i] in obj)) 
      obj[arrayA[i]] = true;
      newArray.push(arrayA[i]);
    
  
  while (j--) 
    if (!(arrayB[j] in obj)) 
      obj[arrayB[j]] = true;
      newArray.push(arrayB[j]);
    
  
  return newArray;

var unionArr = unionArray([34, 35, 45, 48, 49], [44, 55]);
console.log(unionArr);

更快 http://jsperf.com/union-array-faster

【讨论】:

【参考方案14】:

我会先连接数组,然后只返回唯一值。

您必须创建自己的函数才能返回唯一值。既然是好用的功能,不妨add it in as a functionality of the Array

在您使用数组 array1array2 的情况下,它看起来像这样:

    array1.concat(array2) - 连接两个数组 array1.concat(array2).unique() - 仅返回唯一值。这里unique() 是您添加到Array 原型的方法。

整个事情看起来像这样:

Array.prototype.unique = function () 
    var r = new Array();
    o: for(var i = 0, n = this.length; i < n; i++)
    
        for(var x = 0, y = r.length; x < y; x++)
        
            if(r[x]==this[i])
            
                continue o;
            
        
        r[r.length] = this[i];
    
    return r;

var array1 = [34,35,45,48,49];
var array2 = [34,35,45,48,49,55];

// concatenate the arrays then return only the unique values
console.log(array1.concat(array2).unique());

【讨论】:

我更喜欢在这里使用if(r.indexOf(this[i])!==-1) continue; 而不是内部循环和r.push(this[i]) 而不是r[r.length]=this[i] 【参考方案15】:

之前出于同样的原因写过(适用于任意数量的数组):

/**
 * Returns with the union of the given arrays.
 *
 * @param Any amount of arrays to be united.
 * @returns array The union array.
 */
function uniteArrays()

    var union = [];
    for (var argumentIndex = 0; argumentIndex < arguments.length; argumentIndex++)
    
        eachArgument = arguments[argumentIndex];
        if (typeof eachArgument !== 'array')
        
            eachArray = eachArgument;
            for (var index = 0; index < eachArray.length; index++)
            
                eachValue = eachArray[index];
                if (arrayHasValue(union, eachValue) == false)
                union.push(eachValue);
            
        
    

    return union;
    

function arrayHasValue(array, value)
 return array.indexOf(value) != -1; 

【讨论】:

【参考方案16】:

处理合并单个数组值的简单方法。

var values[0] = "id":1235,"name":"value 1"
values[1] = "id":4323,"name":"value 2"

var object=null;
var first=values[0];
for (var i in values) 
 if(i>0)    
 object= $.merge(values[i],first)

【讨论】:

【参考方案17】:

你可以试试这些:

function union(a, b) 
    return a.concat(b).reduce(function(prev, cur) 
        if (prev.indexOf(cur) === -1) prev.push(cur);
        return prev;
    , []);    

function union(a, b) 
    return a.concat(b.filter(function(el) 
        return a.indexOf(el) === -1;
    ));

【讨论】:

【参考方案18】:

ES2015 版本

Array.prototype.diff = function(a) return this.filter(i => a.indexOf(i) < 0);

Array.prototype.union = function(a) return [...this.diff(a), ...a]

【讨论】:

像这样污染原生类型原型是个坏主意... 请解释添加功能如何等同于污染。只要有逻辑推理的支持,就欢迎提出意见。 很公平。我很抱歉发生了什么事。保持个人经历个人化仍然会很好。这不是便笺簿。这是一个质量检查网站。 那太好了。【参考方案19】:

如果你想要一个自定义equals函数来匹配你的元素,你可以在ES2015中使用这个函数:

function unionEquals(left, right, equals)
    return left.concat(right).reduce( (acc,element) => 
        return acc.some(elt => equals(elt, element))? acc : acc.concat(element)
    , []);

它遍历左+右数组。然后对于每个元素,如果在累加器中找不到该元素,则将填充累加器。最后,没有equals 函数指定的重复项。

很漂亮,但对于数千个对象可能不是很有效。

【讨论】:

【参考方案20】:

我认为创建一个新数组是最简单的,只添加由 indexOf 确定的唯一值。

在我看来,这似乎是最直接的解决方案,虽然我不知道它是否是最有效的。不保留排序规则。

var a = [34, 35, 45, 48, 49],
    b = [48, 55];

var c = union(a, b);

function union(a, b)  // will work for n >= 2 inputs
    var newArray = [];

    //cycle through input arrays
    for (var i = 0, l = arguments.length; i < l; i++) 

        //cycle through each input arrays elements
        var array = arguments[i];
        for (var ii = 0, ll = array.length; ii < ll; ii++) 
            var val = array[ii];

            //only add elements to the new array if they are unique
            if (newArray.indexOf(val) < 0) newArray.push(val);
        
    
    return newArray;

【讨论】:

【参考方案21】:
[i for( i of new Set(array1.concat(array2)))]

让我为你分解一下

// This is a list by comprehension
// Store each result in an element of the array
[i
// will be placed in the variable "i", for each element of...
    for( i of
    // ... the Set which is made of...
            new Set(
                // ...the concatenation of both arrays
                array1.concat(array2)
            )
    )
]

换句话说,它首先连接两者,然后删​​除重复项(一个集合,根据定义不能有重复项)

但请注意,在这种情况下,元素的顺序并不能保证。

【讨论】:

以上是关于在JavaScript中获得两个数组的联合[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在javascript中添加两个空白对象或空白数组[重复]

forEach 在javascript中同时循环遍历两个数组[重复]

将两个javascript数组加在一起[重复]

如果对象数组中两个不同对象的两个键在JavaScript中相同,则通过键查找对象[重复]

JavaScript删除两个数组中重复的向

我如何在Javascript中拥有可变长度数组的前3个元素[重复]