Javascript获取三个数组的共同元素

Javascript Get the common elements of three arrays

我正在尝试过滤 3 个数组的公共元素。但是它不是获取 3 个数组的公共元素,而是只读取 2 个数组而不是第 3 个数组。这是我的代码,谢谢:

function commonElementsOfArray(arr1, arr2, arr3) {
    return arr1.filter(function (n) {
        return arr2.indexOf(n) !== -1;
        return arr3.indexOf(n) !== -1;
    });
}

如何将 OP 代码重构为通用相交功能,该功能实现两个数组的简化相交功能,并通过处理通用函数(数组)的 reduce 任务生成 2 个以上数组的整体交集类型)参数?

因此,两个数组的交集将基于 OP 的代码 filter approach but using includes instead of indexOf。像...

function getIntersectionOfTwo(a, b) {
  return a.filter(function (n) {
    return b.includes(n);
  });
}

泛型 getIntersection 然后只需要确保其参数的类型安全和正确的 return 参数太少的值以及正确提供的参数的最小数量的交集结果...

function getIntersection(...listOfArrays) {
  function getIntersectionOfTwo(a, b) {
    return a.filter(function (n) {
      return b.includes(n);
    });
  }
  // assure only array type arguments.
  listOfArrays = listOfArrays.filter(Array.isArray);

  return (listOfArrays[1] ?? listOfArrays[0])
    && listOfArrays.reduce(getIntersectionOfTwo);   
}

console.log(
  'getIntersection() ...',
  getIntersection()
);
console.log(
  'getIntersection(9, "foo", 0) ...',
  getIntersection(9, "foo", 0)
);
console.log(
  'getIntersection([2, 7, 0], "bar") ...',
  getIntersection([2, 7, 0], "bar")
);
console.log(
  'getIntersection([2, 7, 0, 4], [6, 2, 7, 3]) ...',
  getIntersection([2, 7, 0, 4], [6, 2, 7, 3])
);
console.log(
  'getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9, 1, 2]) ...',
  getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9, 1, 2])
);
console.log(
  'getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9]) ...',
  getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9])
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

以上示例对 getIntersectionOfTwo of cause 的实现保持简单,以便更好地理解整个任务的重构过程。

在下一个重构步骤中,也可以改进此功能,以便更有效地 handle/process 大量数组数据。因此,人们会在 filter 回调中使用基于 Map 的查找,而不是在每个 filter 迭代中搜索是否 b.includes(n).

function getIntersection(...listOfArrays) {
  function getIntersectionOfTwo(intersection, iterableItem) {
    // in order to compare huge arrays more efficiently access ...
    const [

      comparisonBase, // ... the shorter one as comparison base
      comparisonList, // ... and the longer one to filter from.

    ] = [intersection, iterableItem]
      .sort((a, b) => a.length - b.length);

    // create a `Map` based lookup table from the shorter array.
    const itemLookup = comparisonBase
      .reduce((map, item) => map.set(item, true), new Map)

    // the intersection is the result of following filter task.
    return comparisonList.filter(item => itemLookup.has(item));
  }
  // assure only array type arguments.
  listOfArrays = listOfArrays.filter(Array.isArray);

  return (listOfArrays[1] ?? listOfArrays[0])
    && listOfArrays.reduce(getIntersectionOfTwo);   
}

console.log(
  'getIntersection() ...',
  getIntersection()
);
console.log(
  'getIntersection(9, "foo", 0) ...',
  getIntersection(9, "foo", 0)
);
console.log(
  'getIntersection([2, 7, 0], "bar") ...',
  getIntersection([2, 7, 0], "bar")
);
console.log(
  'getIntersection([2, 7, 0, 4], [6, 2, 7, 3]) ...',
  getIntersection([2, 7, 0, 4], [6, 2, 7, 3])
);
console.log(
  'getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9, 1, 2]) ...',
  getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9, 1, 2])
);
console.log(
  'getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9]) ...',
  getIntersection([2, 7, 0, 4], [6, 2, 7, 3], [9])
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

如@Titus 所述,您的代码中的问题是双 return 语句 - 一旦找到第一个 return,过滤函数将退出。

但是,在您寻找关于 Array.indexOf 的共同元素的方法中,还有一个值得指出的问题。问题是 Array.indexOf 是一个 O(n) 操作,这意味着将针对 arr2 的每个元素和 arr3 的每个元素检查参数。从表面上看,这听起来像是正确的方法,但如果数组很大,那么这将是一个非常慢的函数。例如,如果每个数组有 1,000 个条目 (n),那么您的函数将获取每个元素并与 arr2 和 arr3 (n) 中的所有元素进行比较。导致 O(n^2) 时间复杂度。

一种替代方法是创建一个 Map 并在遍历每个数组时填充它以跟踪条目被看到的次数。查找值现在有 O(1) 运行时间。迭代每个数组的成本仍然是 O(n),但由于快速查找,这变成了 n * 1 操作或 O(n) 时间复杂度。

function commonElementsOfArray(arr1, arr2, arr3) {
  const map = new Map();
  const updateMap = arr => {
    arr.forEach(entry => {
      if (!map.has(entry)) {
        map.set(entry, 1);
      } else {
        let timesSeen = map.get(entry);
        map.set(entry, ++timesSeen);
      }
    });
  };

  updateMap(arr1);
  updateMap(arr2);
  updateMap(arr3);

  map.forEach((count, key) => {
    // remove all entries not seen at least 3 times
    if (count !== 3) {
      map.delete(key);
    }
  });

  return [...map.keys()];
}

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