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

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

并获得

[2, 3]

当前回答

简单性:

// 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使用率 需要理解reduce 需要理解数据流

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

其他回答

下面是underscore.js的实现:

_.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部分- 62

这是一个现代和简单的ES6方式来做,也非常灵活。 它允许您指定多个数组作为与主题数组进行比较的数组,并且可以在包含和独占模式下工作。

// =======================================
// The function
// =======================================

function assoc(subjectArray, otherArrays, { mustBeInAll = true } = {}) {
  return subjectArray.filter((subjectItem) => {
    if (mustBeInAll) {
      return otherArrays.every((otherArray) =>
        otherArray.includes(subjectItem)
      );
    } else {
      return otherArrays.some((otherArray) => otherArray.includes(subjectItem));
    }
  });
}

// =======================================
// The usage
// =======================================

const cheeseList = ["stilton", "edam", "cheddar", "brie"];
const foodListCollection = [
  ["cakes", "ham", "stilton"],
  ["juice", "wine", "brie", "bread", "stilton"]
];

// Output will be: ['stilton', 'brie']
const inclusive = assoc(cheeseList, foodListCollection, { mustBeInAll: false }),

// Output will be: ['stilton']
const exclusive = assoc(cheeseList, foodListCollection, { mustBeInAll: true })

实例:https://codesandbox.io/s/zealous-butterfly-h7dgf?fontsize=14&hidenavigation=1&theme=dark

如果只使用关联数组呢?

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;
}

编辑:

// 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;
}

使用Underscore.js或lodash.js

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

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

// 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;
};

它只适用于可以作为字符串计算的值,你应该将它们作为一个数组传递:

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

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

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

编辑:我只是注意到,这是,在某种程度上,有点bug。

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

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

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

幸运的是,这很容易通过添加二级索引来解决。那就是:

变化:

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

by:

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

,:

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

by:

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

完整的例子:

// 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' ]