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

16 javascript 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"];
Run Code Online (Sandbox Code Playgroud)

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

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

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

["Dummy1", "Dummy2", "Dummy3", equals: function]
Run Code Online (Sandbox Code Playgroud)

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

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

Nin*_*olz 14

你可以只使用Array#reduceArray#filterArray#includes

var array1 = ["Lorem", "ipsum", "dolor"],
    array2 = ["Lorem", "ipsum", "quick", "brown", "foo"],
    array3 = ["Jumps", "Over", "Lazy", "Lorem"],
    array4 = [1337, 420, 666, "Lorem"],
    data = [array1, array2, array3, array4],
    result = data.reduce((a, b) => a.filter(c => b.includes(c)));

console.log(result);
Run Code Online (Sandbox Code Playgroud)

  • 这个函数的数学复杂度是多少?看起来至少是 O(n²)。 (3认同)
  • 我认为 *O(n * log n)* 是正确的。我认为进一步优化该解决方案的一件事是首先找到最短的数组并将其移动到数据数组的第一个索引。在reduce函数中,我们使用data中的第一个元素作为起点,然后检查该数组中的每个元素。如果初始数组尽可能短,则删除额外的迭代。例如,假设我们的数据数组如下所示: [[1, 2, 3, .... , 10000], [1]] 交换这两个元素的顺序会产生很大的差异。很好的解决方案,@NinaScholz! (2认同)

Arg*_*g0n 8

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

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;
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

intersection(array1, array2, array3, array4); //["Lorem"]
Run Code Online (Sandbox Code Playgroud)

或者像这样:

intersection([array1, array2, array3, array4]); //["Lorem"]
Run Code Online (Sandbox Code Playgroud)

完整代码在这里

更新1

这里使用的实现略小一些filter


198*_*983 6

如果您喜欢使用一些递归和新的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));
Run Code Online (Sandbox Code Playgroud)