关于数据结构:javascript中数组交集的最简单代码

Simplest code for array intersection in javascript

在javascript中实现数组交叉的最简单,无库的代码是什么? 我想写

1
intersection([1,2,3], [2,3,4,5])

得到

1
[2, 3]


使用Array.prototype.filterArray.prototype.indexOf的组合:

1
array1.filter(value => -1 !== array2.indexOf(value))

或者正如vrugtehagel在评论中建议的那样,你可以使用更新的Array.prototype.includes来获得更简单的代码:

1
array1.filter(value => array2.includes(value))

对于旧浏览器:

1
2
3
array1.filter(function(n) {
    return array2.indexOf(n) !== -1;
});


破坏性似乎最简单,特别是如果我们可以假设输入已排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* destructively finds the intersection of
 * two arrays in a simple fashion.  
 *
 * PARAMS
 *  a - first array, must already be sorted
 *  b - second array, must already be sorted
 *
 * NOTES
 *  State of input arrays is undefined when
 *  the function returns.  They should be
 *  (prolly) be dumped.
 *
 *  Should have O(n) operations, where n is
 *    n = MIN(a.length, b.length)
 */

function intersection_destructive(a, b)
{
  var result = [];
  while( a.length > 0 && b.length > 0 )
  {  
     if      (a[0] < b[0] ){ a.shift(); }
     else if (a[0] > b[0] ){ b.shift(); }
     else /* they're equal */
     {
       result.push(a.shift());
       b.shift();
     }
  }

  return result;
}

非破坏性必须是一个更复杂的头发,因为我们必须跟踪索引:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* finds the intersection of
 * two arrays in a simple fashion.  
 *
 * PARAMS
 *  a - first array, must already be sorted
 *  b - second array, must already be sorted
 *
 * NOTES
 *
 *  Should have O(n) operations, where n is
 *    n = MIN(a.length(), b.length())
 */

function intersect_safe(a, b)
{
  var ai=0, bi=0;
  var result = [];

  while( ai < a.length && bi < b.length )
  {
     if      (a[ai] < b[bi] ){ ai++; }
     else if (a[ai] > b[bi] ){ bi++; }
     else /* they're equal */
     {
       result.push(a[ai]);
       ai++;
       bi++;
     }
  }

  return result;
}


如果您的环境支持ECMAScript 6 Set,那么一种简单且有效的(参见规范链接)方式:

1
2
3
4
5
6
function intersect(a, b) {
  var setA = new Set(a);
  var setB = new Set(b);
  var intersection = new Set([...setA].filter(x => setB.has(x)));
  return Array.from(intersection);
}

更短,但可读性更低(也没有创建额外的交集Set):

1
2
3
function intersect(a, b) {
      return [...new Set(a)].filter(x => new Set(b).has(x));
}

每次从b避免新的Set

1
2
3
4
function intersect(a, b) {
      var setB = new Set(b);
      return [...new Set(a)].filter(x => setB.has(x));
}

请注意,使用集合时,您将只获得不同的值,因此new Set[1,2,3,3].size的计算结果为3


使用Underscore.js或lodash.js

1
_.intersection( [0,345,324] , [1,0,324] )  // gives [0,324]


我在ES6方面的贡献。通常,它会找到一个数组的交集,该数组具有作为参数提供的无限数量的数组。

1
2
3
4
5
6
7
Array.prototype.intersect = function(...a) {
  return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
}
var arrs = [[0,2,4,6,8],[4,5,6,7],[4,6]],
     arr = [0,1,2,3,4,5,6,7,8,9];

document.write("[cc lang="javascript"]" + JSON.stringify(arr.intersect(...arrs)) +"

");


如何使用关联数组呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function intersect(a, b) {
    var d1 = {};
    var d2 = {};
    var results = [];
    for (var i = 0; i < a.length; i++) {
        d1[a[i]] = true;
    }
    for (var j = 0; j < b.length; j++) {
        d2[b[j]] = true;
    }
    for (var k in d1) {
        if (d2[k])
            results.push(k);
    }
    return results;
}

编辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
// new version
function intersect(a, b) {
    var d = {};
    var results = [];
    for (var i = 0; i < b.length; i++) {
        d[b[i]] = true;
    }
    for (var j = 0; j < a.length; j++) {
        if (d[a[j]])
            results.push(a[j]);
    }
    return results;
}


使用jQuery:

1
2
3
4
var a = [1,2,3];
var b = [2,3,4,5];
var c = $(b).not($(b).not(a));
alert(c);


通过使用.pop而不是.shift,可以改善@ atk对基元排序数组的实现性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function intersect(array1, array2) {
   var result = [];
   // Don't destroy the original arrays
   var a = array1.slice(0);
   var b = array2.slice(0);
   var aLast = a.length - 1;
   var bLast = b.length - 1;
   while (aLast >= 0 && bLast >= 0) {
      if (a[aLast] > b[bLast] ) {
         a.pop();
         aLast--;
      } else if (a[aLast] < b[bLast] ){
         b.pop();
         bLast--;
      } else /* they're equal */ {
         result.push(a.pop());
         b.pop();
         aLast--;
         bLast--;
      }
   }
   return result;
}

我使用jsPerf创建了一个基准:http://bit.ly/P9FrZK。它的使用速度快了三倍.pop。


1
2
3
4
5
6
7
// Return elements of array a that are also in b in linear time:
function intersect(a, b) {
  return a.filter(Set.prototype.has, new Set(b));
}

// Example:
console.log(intersect([1,2,3], [2,3,4,5]));

我推荐以上简洁的解决方案,它在大输入上优于其他实现。如果小投入的表现很重要,请查看以下备选方案。

替代方案和性能比较:

有关替代实施的信息,请参阅以下代码段,并检查https://jsperf.com/array-intersection-comparison以进行性能比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function intersect_for(a, b) {
  const result = [];
  const alen = a.length;
  const blen = b.length;
  for (let i = 0; i < alen; ++i) {
    const ai = a[i];
    for (let j = 0; j < blen; ++j) {
      if (ai === b[j]) {
        result.push(ai);
        break;
      }
    }
  }
  return result;
}

function intersect_filter_indexOf(a, b) {
  return a.filter(el => b.indexOf(el) !== -1);
}

function intersect_filter_in(a, b) {
  const map = b.reduce((map, el) => {map[el] = true; return map}, {});
  return a.filter(el => el in map);
}

function intersect_for_in(a, b) {
  const result = [];
  const map = {};
  for (let i = 0, length = b.length; i < length; ++i) {
    map[b[i]] = true;
  }
  for (let i = 0, length = a.length; i < length; ++i) {
    if (a[i] in map) result.push(a[i]);
  }
  return result;
}

function intersect_filter_includes(a, b) {
  return a.filter(el => b.includes(el));
}

function intersect_filter_has_this(a, b) {
  return a.filter(Set.prototype.has, new Set(b));
}

function intersect_filter_has_arrow(a, b) {
  const set = new Set(b);
  return a.filter(el => set.has(el));
}

function intersect_for_has(a, b) {
  const result = [];
  const set = new Set(b);
  for (let i = 0, length = a.length; i < length; ++i) {
    if (set.has(a[i])) result.push(a[i]);
  }
  return result;
}

Firefox 53中的结果:

  • 大型阵列上的Ops / sec(10,000个元素):

    1
    2
    3
    4
    5
    6
    7
    filter + has (this)               523 (this answer)
    for + has                         482
    for-loop + in                     279
    filter + in                       242
    for-loops                          24
    filter + includes                  14
    filter + indexOf                   10
  • 小数组上的Ops / sec(100个元素):

    1
    2
    3
    4
    5
    6
    7
    for-loop + in                 384,426
    filter + in                   192,066
    for-loops                     159,137
    filter + includes             104,068
    filter + indexOf               71,598
    filter + has (this)            43,531 (this answer)
    filter + has (arrow function)  35,588


  • 解决
  • 从索引0逐个检查,从中创建新数组。
  • 像这样的东西,虽然测试不好。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function intersection(x,y){
     x.sort();y.sort();
     var i=j=0;ret=[];
     while(i<x.length && j<y.length){
      if(x[i]<y[j])i++;
      else if(y[j]<x[i])j++;
      else {
       ret.push(x[i]);
       i++,j++;
      }
     }
     return ret;
    }

    alert(intersection([1,2,3], [2,3,4,5]));

    PS:该算法仅适用于Numbers和Normal Strings,仲裁对象数组的交集可能不起作用。


    对于仅包含字符串或数字的数组,您可以根据其他一些答案对排序执行某些操作。对于任意对象数组的一般情况,我认为你不能避免长期使用它。以下将为您提供作为arrayIntersection参数提供的任意数量的数组的交集:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    var arrayContains = Array.prototype.indexOf ?
        function(arr, val) {
            return arr.indexOf(val) > -1;
        } :
        function(arr, val) {
            var i = arr.length;
            while (i--) {
                if (arr[i] === val) {
                    return true;
                }
            }
            return false;
        };

    function arrayIntersection() {
        var val, arrayCount, firstArray, i, j, intersection = [], missing;
        var arrays = Array.prototype.slice.call(arguments); // Convert arguments into a real array

        // Search for common values
        firstArray = arrays.pop();
        if (firstArray) {
            j = firstArray.length;
            arrayCount = arrays.length;
            while (j--) {
                val = firstArray[j];
                missing = false;

                // Check val is present in each remaining array
                i = arrayCount;
                while (!missing && i--) {
                    if ( !arrayContains(arrays[i], val) ) {
                        missing = true;
                    }
                }
                if (!missing) {
                    intersection.push(val);
                }
            }
        }
        return intersection;
    }

    arrayIntersection( [1, 2, 3,"a"], [1,"a", 2], ["a", 1] ); // Gives [1,"a"];


    使用ES2015和Sets非常简短。接受类似于String的类似数组的值并删除重复项。

    1
    2
    3
    4
    5
    6
    7
    8
    let intersection = function(a, b) {
      a = new Set(a), b = new Set(b);
      return [...a].filter(v => b.has(v));
    };

    console.log(intersection([1,2,1,2,3], [2,3,5,4,5,3]));

    console.log(intersection('ccaabbab', 'addb').join(''));


    对这里最小的一个微调(filter / indexOf解决方案),即使用JavaScript对象在其中一个数组中创建值的索引,将从O(N * M)减少到"可能"的线性时间。 source1 source2

    1
    2
    3
    4
    5
    function intersect(a, b) {
      var aa = {};
      a.forEach(function(v) { aa[v]=1; });
      return b.filter(function(v) { return v in aa; });
    }

    这不是最简单的解决方案(它比filter + indexOf更多的代码),也不是最快的(可能是一个常数因子比intersect_safe()更慢),但似乎是一个非常好的平衡。它非常简单,同时提供良好的性能,并且不需要预先排序的输入。


    另一种能够同时处理任意数量数组的索引方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // Calculate intersection of multiple array or object values.
    function intersect (arrList) {
        var arrLength = Object.keys(arrList).length;
            // (Also accepts regular objects as input)
        var index = {};
        for (var i in arrList) {
            for (var j in arrList[i]) {
                var v = arrList[i][j];
                if (index[v] === undefined) index[v] = 0;
                index[v]++;
            };
        };
        var retv = [];
        for (var i in index) {
            if (index[i] == arrLength) retv.push(i);
        };
        return retv;
    };

    它仅适用于可以作为字符串计算的值,您应该将它们作为数组传递,如:

    1
    intersect ([arr1, arr2, arr3...]);

    ...但它透明地接受对象作为参数或任何要交叉的元素(总是返回公共值的数组)。例子:

    1
    2
    intersect ({foo: [1, 2, 3, 4], bar: {a: 2, j:4}}); // [2, 4]
    intersect ([{x:"hello", y:"world"}, ["hello","user"]]); // ["hello"]

    编辑:我刚刚注意到,这在某种程度上是略有错误。

    那就是:我编码认为输入数组本身不能包含重复(如提供的示例所示)。

    但是如果输入数组恰好包含重复,那么会产生错误的结果。示例(使用以下实现):

    1
    2
    3
    intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]);
    // Expected: [ '1' ]
    // Actual: [ '1', '3' ]

    幸运的是,只需添加第二级索引即可轻松解决此问题。那是:

    更改:

    1
    2
            if (index[v] === undefined) index[v] = 0;
            index[v]++;

    通过:

    1
    2
            if (index[v] === undefined) index[v] = {};
            index[v][i] = true; // Mark as present in i input.

    ...和:

    1
             if (index[i] == arrLength) retv.push(i);

    通过:

    1
             if (Object.keys(index[i]).length == arrLength) retv.push(i);

    完整的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // Calculate intersection of multiple array or object values.
    function intersect (arrList) {
        var arrLength = Object.keys(arrList).length;
            // (Also accepts regular objects as input)
        var index = {};
        for (var i in arrList) {
            for (var j in arrList[i]) {
                var v = arrList[i][j];
                if (index[v] === undefined) index[v] = {};
                index[v][i] = true; // Mark as present in i input.
            };
        };
        var retv = [];
        for (var i in index) {
            if (Object.keys(index[i]).length == arrLength) retv.push(i);
        };
        return retv;
    };

    intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]); // [ '1' ]


    由于您的数据有一些限制,您可以在线性时间内完成!

    对于正整数:使用将值映射到"看到/未看到"布尔值的数组。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function intersectIntegers(array1,array2) {
       var seen=[],
           result=[];
       for (var i = 0; i < array1.length; i++) {
         seen[array1[i]] = true;
       }
       for (var i = 0; i < array2.length; i++) {
         if ( seen[array2[i]])
            result.push(array2[i]);
       }
       return result;
    }

    对象有一种类似的技术:获取一个虚拟键,为array1中的每个元素设置为"true",然后在array2的元素中查找该键。完成后清理。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function intersectObjects(array1,array2) {
       var result=[];
       var key="tmpKey_intersect"
       for (var i = 0; i < array1.length; i++) {
         array1[i][key] = true;
       }
       for (var i = 0; i < array2.length; i++) {
         if (array2[i][key])
            result.push(array2[i]);
       }
       for (var i = 0; i < array1.length; i++) {
         delete array1[i][key];
       }
       return result;
    }

    当然你需要确保密钥没有出现,否则你将破坏你的数据......


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function intersection(A,B){
    var result = new Array();
    for (i=0; i<A.length; i++) {
        for (j=0; j<B.length; j++) {
            if (A[i] == B[j] && $.inArray(A[i],result) == -1) {
                result.push(A[i]);
            }
        }
    }
    return result;
    }

    这可能是最简单的一个,
    除了list1.filter(n => list2.includes(n))

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var list1 = ['bread', 'ice cream', 'cereals', 'strawberry', 'chocolate']
    var list2 = ['bread', 'cherry', 'ice cream', 'oats']

    function check_common(list1, list2){
       
        list3 = []
        for (let i=0; i<list1.length; i++){
           
            for (let j=0; j<list2.length; j++){
                if (list1[i] === list2[j]){
                    list3.push(list1[i]);              
                }      
            }
           
        }
        return list3
       
    }

    check_common(list1, list2) // ["bread","ice cream"]


    我会为最适合我的事情做出贡献:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    if (!Array.prototype.intersect){
    Array.prototype.intersect = function (arr1) {

        var r = [], o = {}, l = this.length, i, v;
        for (i = 0; i < l; i++) {
            o[this[i]] = true;
        }
        l = arr1.length;
        for (i = 0; i < l; i++) {
            v = arr1[i];
            if (v in o) {
                r.push(v);
            }
        }
        return r;
    };
    }

    您可以使用(对于IE以外的所有浏览器):

    1
    const intersection = array1.filter(element => array2.includes(element));

    或IE:

    1
    const intersection = array1.filter(element => array2.indexOf(element) !== -1);

    "indexOf"适用于IE 9.0,chrome,firefox,opera,

    1
    2
    3
    4
    5
    6
    7
    8
        function intersection(a,b){
         var rs = [], x = a.length;
         while (x--) b.indexOf(a[x])!=-1 && rs.push(a[x]);
         return rs.sort();
        }

    intersection([1,2,3], [2,3,4,5]);
    //Result:  [2,3]

    ES2015的功能方法

    功能方法必须考虑仅使用没有副作用的纯函数,每个函数仅涉及单个作业。

    这些限制增强了所涉及功能的可组合性和可重用性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // small, reusable auxiliary functions

    const createSet = xs => new Set(xs);
    const filter = f => xs => xs.filter(apply(f));
    const apply = f => x => f(x);


    // intersection

    const intersect = xs => ys => {
      const zs = createSet(ys);
      return filter(x => zs.has(x)
         ? true
         : false
      ) (xs);
    };


    // mock data

    const xs = [1,2,2,3,4,5];
    const ys = [0,1,2,3,3,3,6,7,8,9];


    // run it

    console.log( intersect(xs) (ys) );

    请注意,使用原生Set类型,这是有利的
    查找性能。

    避免重复

    显然,保留了来自第一个Array的重复出现的项目,而第二个Array被去重复。这可能是或可能不是期望的行为。如果您需要唯一的结果,只需将dedupe应用于第一个参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    // auxiliary functions

    const apply = f => x => f(x);
    const comp = f => g => x => f(g(x));
    const afrom = apply(Array.from);
    const createSet = xs => new Set(xs);
    const filter = f => xs => xs.filter(apply(f));


    // intersection

    const intersect = xs => ys => {
      const zs = createSet(ys);
      return filter(x => zs.has(x)
         ? true
         : false
      ) (xs);
    };


    // de-duplication

    const dedupe = comp(afrom) (createSet);


    // mock data

    const xs = [1,2,2,3,4,5];
    const ys = [0,1,2,3,3,3,6,7,8,9];


    // unique result

    console.log( intersect(dedupe(xs)) (ys) );

    计算任意数量Array的交集

    如果要计算任意数量的Array s的交集,只需将intersectfoldl组合。这是一个便利功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // auxiliary functions

    const apply = f => x => f(x);
    const uncurry = f => (x, y) => f(x) (y);
    const createSet = xs => new Set(xs);
    const filter = f => xs => xs.filter(apply(f));
    const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);


    // intersection

    const intersect = xs => ys => {
      const zs = createSet(ys);
      return filter(x => zs.has(x)
         ? true
         : false
      ) (xs);
    };


    // intersection of an arbitrarily number of Arrays

    const intersectn = (head, ...tail) => foldl(intersect) (head) (tail);


    // mock data

    const xs = [1,2,2,3,4,5];
    const ys = [0,1,2,3,3,3,6,7,8,9];
    const zs = [0,1,2,3,4,5,6];


    // run

    console.log( intersectn(xs, ys, zs) );


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    'use strict'

    // Example 1
    function intersection(a1, a2) {
        return a1.filter(x => a2.indexOf(x) > -1)
    }

    // Example 2 (prototype function)
    Array.prototype.intersection = function(arr) {
        return this.filter(x => arr.indexOf(x) > -1)
    }

    const a1 = [1, 2, 3]
    const a2 = [2, 3, 4, 5]

    console.log(intersection(a1, a2))
    console.log(a1.intersection(a2))


    为简单起见:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // Usage
    const intersection = allLists
      .reduce(intersect, allValues)
      .reduce(removeDuplicates, []);


    // Implementation
    const intersect = (intersection, list) =>
      intersection.filter(item =>
        list.some(x => x === item));

    const removeDuplicates = (uniques, item) =>
      uniques.includes(item) ? uniques : uniques.concat(item);


    // Example Data
    const somePeople = [bob, doug, jill];
    const otherPeople = [sarah, bob, jill];
    const morePeople = [jack, jill];

    const allPeople = [...somePeople, ...otherPeople, ...morePeople];
    const allGroups = [somePeople, otherPeople, morePeople];

    // Example Usage
    const intersection = allGroups
      .reduce(intersect, allPeople)
      .reduce(removeDuplicates, []);

    intersection; // [jill]

    优点:

    • 泥土简单
    • 数据中心
    • 适用于任意数量的列表
    • 适用于任意长度的列表
    • 适用于任意类型的值
    • 适用于任意排序顺序
    • 保留形状(任何阵列中首次出现的顺序)
    • 尽可能早地退出
    • 内存安全,没有篡改功能/数组原型

    缺点:

    • 内存使用率更高
    • 更高的CPU使用率
    • 需要了解减少
    • 需要了解数据流

    您不希望将此用于3D引擎或内核工作,但如果您在基于事件的应用程序中运行此问题时遇到问题,则您的设计会遇到更大的问题。


    .reduce构建地图,.filter查找交集。 .filter中的delete允许我们将第二个数组视为唯一集合。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function intersection (a, b) {
      var seen = a.reduce(function (h, k) {
        h[k] = true;
        return h;
      }, {});

      return b.filter(function (k) {
        var exists = seen[k];
        delete seen[k];
        return exists;
      });
    }

    我发现这种方法很容易推理。它在恒定的时间内执行。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function getIntersection(arr1, arr2){
        var result = [];
        arr1.forEach(function(elem){
            arr2.forEach(function(elem2){
                if(elem === elem2){
                    result.push(elem);
                }
            });
        });
        return result;
    }

    getIntersection([1,2,3], [2,3,4,5]); // [ 2, 3 ]

    而是使用indexOf,您也可以使用Array.protype.includes。

    1
    2
    3
    4
    5
    6
    7
    function intersection(arr1, arr2) {
      return arr1.filter((ele => {
        return arr2.includes(ele);
      }));
    }

    console.log(intersection([1,2,3], [2,3,4,5]));


    1
    2
    3
    4
    var listA = [1,2,3,4,5,6,7];
    var listB = [2,4,6,8];

    var result = listA.filter(itemA => listB.some(itemB => itemB === itemA));


    这是underscore.js实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    _.intersection = function(array) {
      if (array == null) return [];
      var result = [];
      var argsLength = arguments.length;
      for (var i = 0, length = array.length; i < length; i++) {
        var item = array[i];
        if (_.contains(result, item)) continue;
        for (var j = 1; j < argsLength; j++) {
          if (!_.contains(arguments[j], item)) break;
        }
        if (j === argsLength) result.push(item);
      }
      return result;
    };

    资料来源:http://underscorejs.org/docs/underscore.html#section-62


    如果要使用已接受的答案,但需要支持Internet Explorer,则必须避免使用箭头功能速记注释。这是编辑过的单行程序,也可以在IE中使用:

    1
    2
    3
    // accepted aswer: array1.filter(value => -1 !== array2.indexOf(value));
    // IE-supported syntax:
    array1.filter(function(value) { return -1 !== array2.indexOf(value) });

    如果你需要让它处理多个数组:

    1
    2
    3
    4
    5
    6
    const intersect = (a, b, ...rest) => {
      if (rest.length === 0) return [...new Set(a)].filter(x => new Set(b).has(x));
      return intersect(a, intersect(b, ...rest));
    };

    console.log(intersect([1,2,3,4,5], [1,2], [1, 2, 3,4,5], [2, 10, 1])) // [1,2]


    ES6风格简约的方式。

    1
    2
    3
    4
    const intersection = (a, b) => {
      const s = new Set(b);
      return a.filter(x => s.has(x));
    };

    例:

    1
    intersection([1, 2, 3], [4, 3, 2]); // [2, 3]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var arrays = [
        [1, 2, 3],
        [2, 3, 4, 5]
    ]
    function commonValue (...arr) {
        let res = arr[0].filter(function (x) {
            return arr.every((y) => y.includes(x))
        })
        return res;
    }
    commonValue(...arrays);


    您可以使用Set作为Array#filterthisArg并将Set#has作为回调。

    1
    2
    3
    4
    5
    function intersection(a, b) {
        return a.filter(Set.prototype.has, new Set(b));
    }

    console.log(intersection([1, 2, 3], [2, 3, 4, 5]));


    我编写了一个intesection函数,它甚至可以根据这些对象的特定属性检测对象数组的交集。

    例如,

    1
    2
    if arr1 = [{id: 10}, {id: 20}]
    and arr2 =  [{id: 20}, {id: 25}]

    我们想要基于id属性的交集,那么输出应该是:

    1
    [{id: 20}]

    因此,相同的功能(注意:ES6代码)是:

    1
    2
    3
    4
    5
    const intersect = (arr1, arr2, accessors = [v => v, v => v]) => {
        const [fn1, fn2] = accessors;
        const set = new Set(arr2.map(v => fn2(v)));
        return arr1.filter(value => set.has(fn1(value)));
    };

    你可以把这个函数称为:

    1
    intersect(arr1, arr2, [elem => elem.id, elem => elem.id])

    另请注意:此函数在考虑第一个数组是主数组时找到交集,因此交集结果将是主数组的交集结果。


    1
    2
    3
    function intersectionOfArrays(arr1, arr2) {
        return arr1.filter((element) => arr2.indexOf(element) !== -1).filter((element, pos, self) => self.indexOf(element) == pos);
    }

    这是我正在使用的一个非常天真的实现。它是非破坏性的,也确保不复制entires。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Array.prototype.contains = function(elem) {
        return(this.indexOf(elem) > -1);
    };

    Array.prototype.intersect = function( array ) {
        // this is naive--could use some optimization
        var result = [];
        for ( var i = 0; i < this.length; i++ ) {
            if ( array.contains(this[i]) && !result.contains(this[i]) )
                result.push( this[i] );
        }
        return result;
    }

    使用一个数组创建一个Object并循环遍历第二个数组以检查该值是否作为键存在。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function intersection(arr1, arr2) {
      var myObj = {};
      var myArr = [];
      for (var i = 0, len = arr1.length; i < len; i += 1) {
        if(myObj[arr1[i]]) {
          myObj[arr1[i]] += 1;
        } else {
          myObj[arr1[i]] = 1;
        }
      }
      for (var j = 0, len = arr2.length; j < len; j += 1) {
        if(myObj[arr2[j]] && myArr.indexOf(arr2[j]) === -1) {
          myArr.push(arr2[j]);
        }
      }
      return myArr;
    }

    如果第二个数组总是作为一个集处理,则不需要在函数内部为第二个数组声明一个中间变量。

    以下解决方案返回两个数组中出现的唯一值数组:

    1
    2
    3
    4
    5
    6
    const intersection = (a, b) => {
      b = new Set(b); // recycling variable
      return [...new Set(a)].filter(e => b.has(e));
    };

    console.log(intersection([1, 2, 3, 1, 1], [1, 2, 4])); // Array [ 1, 2 ]

    coffeescript中N个数组的交集

    1
    2
    3
    4
    5
    6
    7
    8
    getIntersection: (arrays) ->
        if not arrays.length
            return []
        a1 = arrays[0]
        for a2 in arrays.slice(1)
            a = (val for val in a1 when val in a2)
            a1 = a
        return a1.unique()

    如果您的数组已排序,则应在O(n)中运行,其中n为min(a.length,b.length)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function intersect_1d( a, b ){
        var out=[], ai=0, bi=0, acurr, bcurr, last=Number.MIN_SAFE_INTEGER;
        while( ( acurr=a[ai] )!==undefined && ( bcurr=b[bi] )!==undefined ){
            if( acurr < bcurr){
                if( last===acurr ){
                    out.push( acurr );
                }
                last=acurr;
                ai++;
            }
            else if( acurr > bcurr){
                if( last===bcurr ){
                    out.push( bcurr );
                }
                last=bcurr;
                bi++;
            }
            else {
                out.push( acurr );
                last=acurr;
                ai++;
                bi++;
            }
        }
        return out;
    }

    以下代码也删除了重复项:

    1
    2
    3
    4
    5
    6
           function intersect(x, y) {
                if (y.length > x.length) temp = y, y = x, x= temp;  
                return x.filter(function (e, i, c) {  
                      return c.indexOf(e) === i;
                     });
           }

    我扩展了tarulen的答案,可以使用任意数量的数组。它也应该使用非整数值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function intersect() {
        const last = arguments.length - 1;
        var seen={};
        var result=[];
        for (var i = 0; i < last; i++)   {
            for (var j = 0; j < arguments[i].length; j++)  {
                if (seen[arguments[i][j]])  {
                    seen[arguments[i][j]] += 1;
                }
                else if (!i)    {
                    seen[arguments[i][j]] = 1;
                }
            }
        }
        for (var i = 0; i < arguments[last].length; i++) {
            if ( seen[arguments[last][i]] === last)
                result.push(arguments[last][i]);
            }
        return result;
    }

    希望这有助于所有版本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    function diffArray(arr1, arr2) {
      var newArr = [];

      var large = arr1.length>=arr2.length?arr1:arr2;
      var small = JSON.stringify(large) == JSON.stringify(arr1)?arr2:arr1;
      for(var i=0;i<large.length;i++){
        var copyExists = false;
        for(var j =0;j<small.length;j++){
          if(large[i]==small[j]){
            copyExists= true;
            break;
          }
        }
        if(!copyExists)
          {
            newArr.push(large[i]);
          }
      }

      for(var i=0;i<small.length;i++){
        var copyExists = false;
        for(var j =0;j<large.length;j++){
          if(large[j]==small[i]){
            copyExists= true;
            break;
          }
        }
        if(!copyExists)
          {
            newArr.push(small[i]);
          }
      }


      return newArr;
    }

    在Anon的优秀答案的基础上,这个返回两个或更多阵列的交集。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function arrayIntersect(arrayOfArrays)
    {        
        var arrayCopy = arrayOfArrays.slice(),
            baseArray = arrayCopy.pop();

        return baseArray.filter(function(item) {
            return arrayCopy.every(function(itemList) {
                return itemList.indexOf(item) !== -1;
            });
        });
    }


    不是效率,而是易于遵循,这里是集合的联合和交集的一个例子,它处理集合和集合的数组。

    http://jsfiddle.net/zhulien/NF68T/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    // process array [element, element...], if allow abort ignore the result
    function processArray(arr_a, cb_a, blnAllowAbort_a)
    {
        var arrResult = [];
        var blnAborted = false;
        var intI = 0;

        while ((intI < arr_a.length) && (blnAborted === false))
        {
            if (blnAllowAbort_a)
            {
                blnAborted = cb_a(arr_a[intI]);
            }
            else
            {
                arrResult[intI] = cb_a(arr_a[intI]);
            }
            intI++;
        }

        return arrResult;
    }

    // process array of operations [operation,arguments...]
    function processOperations(arrOperations_a)
    {
        var arrResult = [];
        var fnOperationE;

        for(var intI = 0, intR = 0; intI < arrOperations_a.length; intI+=2, intR++)
        {
            var fnOperation = arrOperations_a[intI+0];
            var fnArgs = arrOperations_a[intI+1];
            if (fnArgs === undefined)
            {
                arrResult[intR] = fnOperation();
            }
            else
            {
                arrResult[intR] = fnOperation(fnArgs);
            }
        }

        return arrResult;
    }

    // return whether an element exists in an array
    function find(arr_a, varElement_a)
    {
        var blnResult = false;

        processArray(arr_a, function(varToMatch_a)
        {
            var blnAbort = false;

            if (varToMatch_a === varElement_a)
            {
                blnResult = true;
                blnAbort = true;
            }

            return blnAbort;
        }, true);

        return blnResult;
    }

    // return the union of all sets
    function union(arr_a)
    {
        var arrResult = [];
        var intI = 0;

        processArray(arr_a, function(arrSet_a)
        {
            processArray(arrSet_a, function(varElement_a)
            {
                // if the element doesn't exist in our result
                if (find(arrResult, varElement_a) === false)
                {
                    // add it
                    arrResult[intI] = varElement_a;
                    intI++;
                }
            });
        });

        return arrResult;
    }

    // return the intersection of all sets
    function intersection(arr_a)
    {
        var arrResult = [];
        var intI = 0;

        // for each set
        processArray(arr_a, function(arrSet_a)
        {
            // every number is a candidate
            processArray(arrSet_a, function(varCandidate_a)
            {
                var blnCandidate = true;

                // for each set
                processArray(arr_a, function(arrSet_a)
                {
                    // check that the candidate exists
                    var blnFoundPart = find(arrSet_a, varCandidate_a);

                    // if the candidate does not exist
                    if (blnFoundPart === false)
                    {
                        // no longer a candidate
                        blnCandidate = false;
                    }
                });

                if (blnCandidate)
                {
                    // if the candidate doesn't exist in our result
                    if (find(arrResult, varCandidate_a) === false)
                    {
                        // add it
                        arrResult[intI] = varCandidate_a;
                        intI++;
                    }
                }
            });
        });

        return arrResult;
    }

    var strOutput = ''

    var arrSet1 = [1,2,3];
    var arrSet2 = [2,5,6];
    var arrSet3 = [7,8,9,2];

    // return the union of the sets
    strOutput = union([arrSet1, arrSet2, arrSet3]);
    alert(strOutput);

    // return the intersection of 3 sets
    strOutput = intersection([arrSet1, arrSet2, arrSet3]);
    alert(strOutput);

    // of 3 sets of sets, which set is the intersecting set
    strOutput = processOperations([intersection,[[arrSet1, arrSet2], [arrSet2], [arrSet2, arrSet3]]]);
    alert(strOutput);

    IE中的Array不支持"filter"和"indexOf"。这个怎么样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var array1 = [1, 2, 3];
    var array2 = [2, 3, 4, 5];

    var intersection = [];
    for (i in array1) {
        for (j in array2) {
            if (array1[i] == array2[j]) intersection.push(array1[i]);
        }
    }