如何计算JavaScript中多个数组的交集?什么[等于:功能]是什么意思?

时间:2021-01-12 21:22:15

I am aware of this question, simplest code for array intersection but all the solutions presume the number of arrays is two, which cannot be certain in my case.

我知道这个问题,最简单的数组交叉代码,但所有的解决方案都假定数组的数量是两个,这在我的情况下是不可能的。

I have divs on a page with data that contains arrays. I want to find the values common to all arrays. I do not know how many divs/arrays I will have in advance. What is the best way to calculate values common to all arrays?

我在页面上有div包含数组的数据。我想找到所有数组共有的值。我不知道我将提前有多少个div /数组。计算所有数组共有的值的最佳方法是什么?

var array1 = ["Lorem", "ipsum", "dolor"];
var array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
var array3 = ["Jumps", "Over", "Lazy", "Lorem"];
var array4 = [1337, 420, 666, "Lorem"];
//Result should be ["Lorem"];

I found another solution elsewhere, using Underscore.js.

我在其他地方使用Underscore.js找到了另一种解决方案。

var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
_.intersection.apply(_, arrayOfArrays)
//Result is [43]

I've tested this with simple dummy data at my end and it seems to work. But for some reason, some of the arrays I'm producing, which contain simple strings, also automatically include an added value, "equals: function":

我在最后用简单的虚拟数据进行了测试,看起来效果很好。但由于某种原因,我正在生成的一些包含简单字符串的数组也自动包含一个附加值,“equals:function”:

["Dummy1", "Dummy2", "Dummy3", equals: function]

And whenever I use the Underscore.js intersection method, on an array of arrays, I always get [equals: function] in dev tools, and not - if "Dummy3" is common to all arrays - ["Dummy3"].

每当我在一个数组数组上使用Underscore.js交集方法时,我总是在开发工具中得到[equals:function],而不是 - 如果“Dummy3”对所有数组都是通用的 - [“Dummy3”]。

So TL;DR is there another solution to array intersection that would suit my case? And can anyone explain what [equals: function] means here? When I expand the item in the dev tools, it produces an empty array and a list of methods available on arrays (pop, push, shift etc), but these methods are all faded out, while equals: function is highlighted.

那么TL; DR是否有另一种适合我的情况的阵列交叉解决方案?任何人都可以解释[equals:function]在这里意味着什么?当我在开发工具中展开项目时,它会生成一个空数组和数组上可用的方法列表(pop,push,shift等),但这些方法都已淡出,而equals:function则突出显示。

7 个解决方案

#1


3  

I wrote a helper function for this:

我为此写了一个辅助函数:

function intersection() {
  var result = [];
  var lists;

  if(arguments.length === 1) {
    lists = arguments[0];
  } else {
    lists = arguments;
  }

  for(var i = 0; i < lists.length; i++) {
    var currentList = lists[i];
    for(var y = 0; y < currentList.length; y++) {
        var currentValue = currentList[y];
      if(result.indexOf(currentValue) === -1) {
        var existsInAll = true;
        for(var x = 0; x < lists.length; x++) {
          if(lists[x].indexOf(currentValue) === -1) {
            existsInAll = false;
            break;
          }
        }
        if(existsInAll) {
          result.push(currentValue);
        }
      }
    }
  }
  return result;
}

Use it like this:

像这样用它:

intersection(array1, array2, array3, array4); //["Lorem"]

Or like this:

或者像这样:

intersection([array1, array2, array3, array4]); //["Lorem"]

Full code here

完整代码在这里

UPDATE 1

更新1

A slightly smaller implementation here using filter

这里使用过滤器稍微小一些

#2


6  

This can be done pretty succinctly if you fancy employing some recursion and the new ES2015 syntax:

如果您喜欢使用一些递归和新的ES2015语法,这可以非常简洁地完成:

const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];

const arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];

// Filter xs where, for a given x, there exists some y in ys where y === x.
const intersect2 = (xs,ys) => xs.filter(x => ys.some(y => y === x));

// When there is only one array left, return it (the termination condition
// of the recursion). Otherwise first find the intersection of the first
// two arrays (intersect2), then repeat the whole process for that result
// combined with the remaining arrays (intersect). Thus the number of arrays
// passed as arguments to intersect is reduced by one each time, until
// there is only one array remaining.
const intersect = (xs,ys,...rest) => ys === undefined ? xs : intersect(intersect2(xs,ys),...rest);

console.log(intersect(array1, array2, array3, array4));
console.log(intersect(...arrayOfArrays));

// Alternatively, in old money,

var intersect2ES5 = function (xs, ys) {
    return xs.filter(function (x) {
        return ys.some(function (y) {
            return y === x;
        });
    });
};
    
// Changed slightly from above, to take a single array of arrays,
// which matches the underscore.js approach in the Q., and is better anyhow.
var intersectES5 = function (zss) {
    var xs = zss[0];
    var ys = zss[1];
    var rest = zss.slice(2);
    if (ys === undefined) {
        return xs;
    }
    return intersectES5([intersect2ES5(xs, ys)].concat(rest));
};

console.log(intersectES5([array1, array2, array3, array4]));
console.log(intersectES5(arrayOfArrays));

#3


1  

Your code with _lodash is working fine.

使用_lodash的代码工作正常。

As you can say in this fiddle:

你可以在这个小提琴中说:

this code:

这段代码:

var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
var a = _.intersection.apply(_, arrayOfArrays);
console.log(a);
console.log(a.length);

Will have output:

会有输出:

[42]
1

Maybe you see

也许你看到了

equals: function

等于:功能

because you are using kind of debugger.

因为你正在使用一种调试器。

Try to just print the array with console.log, you will get only 42.

尝试使用console.log打印数组,您将只获得42。

#4


1  

Using a combination of ideas from several contributors and the latest ES6 goodness, I arrived at

结合使用了几个贡献者的想法和最新的ES6优点,我来到了

const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];

Array.prototype.intersect = function intersect(a, ...b) {
    const c = function (a, b) {
        b = new Set(b);
        return a.filter((a) => b.has(a));
    };
    return undefined === a ? this : intersect.call(c(this, a), ...b);
};

console.log(array1.intersect(array2, array3, array4));
// ["Lorem"]

#5


0  

For anyone confused by this in the future,

对于任何对此感到困惑的人,

_.intersection.apply(_, arrayOfArrays)

Is in fact the most elegant way to do this. But:

实际上是最优雅的方式。但:

var arrayOfArrays = [[43, 34343, 23232], [43, 314159, 343], [43, 243]];
arrayOfArrays = _.intersection.apply(_, arrayOfArrays);

Will not work! Must do

不管用!必须做

var differentVariableName = _.intersection.apply(_,arrayOfArrays);

#6


0  

Lodash pure:

Lodash纯:

_.keys(_.pickBy(_.groupBy(_.flatten(arrays)), function (e) {return e.length > 1}))

Lodash with plain js:

Lodash与普通的js:

var elements = {}, duplicates = {};
 _.each(arrays, function (array) {
     _.each(array, function (element) {
         if (!elements[element]) {
             elements[element] = true;
         } else {
             duplicates[element] = true;
         }
     });
 });
_.keys(duplicates);

#7


0  

Small recursive divide and conquer solution that does not rely on es6 or any library.

小的递归分而治之的解决方案,不依赖于es6或任何库。

It accepts an array of arrays which makes the code shorter and allows you to pass arguments by using map.

它接受一个数组数组,使代码更短,并允许您使用map传递参数。

function intersection(a) {
    if (a.length > 2)
        return intersection([intersection(a.slice(0, a.length / 2)), intersection(a.slice(a.length / 2))]);

    if (a.length == 1)
        return a[0];

    return a[0].filter(function(item) {
        return a[1].indexOf(item) !== -1;
    });
}

var list1 = [ 'a', 'b', 'c' ];
var list2 = [ 'd', 'b', 'e' ];
var list3 = [ 'f', 'b', 'e' ];
console.log(intersection([list1, list2, list3]));

#1


3  

I wrote a helper function for this:

我为此写了一个辅助函数:

function intersection() {
  var result = [];
  var lists;

  if(arguments.length === 1) {
    lists = arguments[0];
  } else {
    lists = arguments;
  }

  for(var i = 0; i < lists.length; i++) {
    var currentList = lists[i];
    for(var y = 0; y < currentList.length; y++) {
        var currentValue = currentList[y];
      if(result.indexOf(currentValue) === -1) {
        var existsInAll = true;
        for(var x = 0; x < lists.length; x++) {
          if(lists[x].indexOf(currentValue) === -1) {
            existsInAll = false;
            break;
          }
        }
        if(existsInAll) {
          result.push(currentValue);
        }
      }
    }
  }
  return result;
}

Use it like this:

像这样用它:

intersection(array1, array2, array3, array4); //["Lorem"]

Or like this:

或者像这样:

intersection([array1, array2, array3, array4]); //["Lorem"]

Full code here

完整代码在这里

UPDATE 1

更新1

A slightly smaller implementation here using filter

这里使用过滤器稍微小一些

#2


6  

This can be done pretty succinctly if you fancy employing some recursion and the new ES2015 syntax:

如果您喜欢使用一些递归和新的ES2015语法,这可以非常简洁地完成:

const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];

const arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];

// Filter xs where, for a given x, there exists some y in ys where y === x.
const intersect2 = (xs,ys) => xs.filter(x => ys.some(y => y === x));

// When there is only one array left, return it (the termination condition
// of the recursion). Otherwise first find the intersection of the first
// two arrays (intersect2), then repeat the whole process for that result
// combined with the remaining arrays (intersect). Thus the number of arrays
// passed as arguments to intersect is reduced by one each time, until
// there is only one array remaining.
const intersect = (xs,ys,...rest) => ys === undefined ? xs : intersect(intersect2(xs,ys),...rest);

console.log(intersect(array1, array2, array3, array4));
console.log(intersect(...arrayOfArrays));

// Alternatively, in old money,

var intersect2ES5 = function (xs, ys) {
    return xs.filter(function (x) {
        return ys.some(function (y) {
            return y === x;
        });
    });
};
    
// Changed slightly from above, to take a single array of arrays,
// which matches the underscore.js approach in the Q., and is better anyhow.
var intersectES5 = function (zss) {
    var xs = zss[0];
    var ys = zss[1];
    var rest = zss.slice(2);
    if (ys === undefined) {
        return xs;
    }
    return intersectES5([intersect2ES5(xs, ys)].concat(rest));
};

console.log(intersectES5([array1, array2, array3, array4]));
console.log(intersectES5(arrayOfArrays));

#3


1  

Your code with _lodash is working fine.

使用_lodash的代码工作正常。

As you can say in this fiddle:

你可以在这个小提琴中说:

this code:

这段代码:

var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
var a = _.intersection.apply(_, arrayOfArrays);
console.log(a);
console.log(a.length);

Will have output:

会有输出:

[42]
1

Maybe you see

也许你看到了

equals: function

等于:功能

because you are using kind of debugger.

因为你正在使用一种调试器。

Try to just print the array with console.log, you will get only 42.

尝试使用console.log打印数组,您将只获得42。

#4


1  

Using a combination of ideas from several contributors and the latest ES6 goodness, I arrived at

结合使用了几个贡献者的想法和最新的ES6优点,我来到了

const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];

Array.prototype.intersect = function intersect(a, ...b) {
    const c = function (a, b) {
        b = new Set(b);
        return a.filter((a) => b.has(a));
    };
    return undefined === a ? this : intersect.call(c(this, a), ...b);
};

console.log(array1.intersect(array2, array3, array4));
// ["Lorem"]

#5


0  

For anyone confused by this in the future,

对于任何对此感到困惑的人,

_.intersection.apply(_, arrayOfArrays)

Is in fact the most elegant way to do this. But:

实际上是最优雅的方式。但:

var arrayOfArrays = [[43, 34343, 23232], [43, 314159, 343], [43, 243]];
arrayOfArrays = _.intersection.apply(_, arrayOfArrays);

Will not work! Must do

不管用!必须做

var differentVariableName = _.intersection.apply(_,arrayOfArrays);

#6


0  

Lodash pure:

Lodash纯:

_.keys(_.pickBy(_.groupBy(_.flatten(arrays)), function (e) {return e.length > 1}))

Lodash with plain js:

Lodash与普通的js:

var elements = {}, duplicates = {};
 _.each(arrays, function (array) {
     _.each(array, function (element) {
         if (!elements[element]) {
             elements[element] = true;
         } else {
             duplicates[element] = true;
         }
     });
 });
_.keys(duplicates);

#7


0  

Small recursive divide and conquer solution that does not rely on es6 or any library.

小的递归分而治之的解决方案,不依赖于es6或任何库。

It accepts an array of arrays which makes the code shorter and allows you to pass arguments by using map.

它接受一个数组数组,使代码更短,并允许您使用map传递参数。

function intersection(a) {
    if (a.length > 2)
        return intersection([intersection(a.slice(0, a.length / 2)), intersection(a.slice(a.length / 2))]);

    if (a.length == 1)
        return a[0];

    return a[0].filter(function(item) {
        return a[1].indexOf(item) !== -1;
    });
}

var list1 = [ 'a', 'b', 'c' ];
var list2 = [ 'd', 'b', 'e' ];
var list3 = [ 'f', 'b', 'e' ];
console.log(intersection([list1, list2, list3]));