数组数组中的常用值 - lodash

Common values in array of arrays - lodash

我有一个如下所示的数组:

const myArray = [
  [
    {id: 1, name: 'Liam'},
    {id: 2, name: 'Oliver'},
    {id: 3, name: 'Jake'},
  ],
  [
    {id: 1, name: 'Liam'},
    {id: 2, name: 'Oliver'},
    {id: 4, name: 'Joe'},
  ],
]

我需要通过 id 找到公共元素,然后 return 它们在一个数组中,看起来像这样:

[
  {id: 1, name: 'Liam'},
  {id: 2, name: 'Oliver'},
]

如果没有任何方法可以用 lodash 做到这一点,那么 JS 也可以。 请注意,我不知道我将在其中放置多少个这样的数组,因此它应该适用于任何数量。

您可以使用 lodash 的 _.intersectionBy()。你需要传播 myArray 因为 _intersectionBy() 期望数组作为参数,而不是单个数组数组:

const myArray = [[{"id":1,"name":"Liam"},{"id":2,"name":"Oliver"},{"id":3,"name":"Jake"}],[{"id":1,"name":"Liam"},{"id":2,"name":"Oliver"},{"id":4,"name":"Joe"}]]

const result = _.intersectionBy(...myArray, 'id')

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

如今,即使没有实用程序库的帮助,vanilla ES 也非常强大,可以以功能方式处理集合。 您可以使用常规 Array 的方法来获得纯 JS 解决方案。 我用纯 JS 创建了两个示例。 当然,也可以有更多的方法。如果您已经在您的应用程序中使用 Lodash,可能最好只使用上面提出的 _.intersectionBy() 形式的高级实现来降低代码复杂性。

const myArray = [
  [
    {id: 1, name: 'Liam'},
    {id: 2, name: 'Oliver'},
    {id: 3, name: 'Jake'},
  ],
  [
    {id: 1, name: 'Liam'},
    {id: 2, name: 'Oliver'},
    {id: 4, name: 'Joe'},
  ],
];

// Regular functional filter-reduce
const reducer = (accum, x) => {
  return accum.findIndex(y => x.id == y.id) < 0
    ? [...accum, x]
    : accum;
};

const resultFilterReduce = myArray
  .flat()
  .filter(x => myArray.every(y => y.findIndex(obj => obj.id === x.id) > -1))
  .reduce(reducer, []);

console.log(resultFilterReduce);

// Filter-reduce with using of "HashMap" to remove duplicates
const resultWithHashMap = Object.values(
  myArray
    .flat()
    .filter(x => myArray.every(y => y.findIndex(obj => obj.id === x.id) > -1))
    .reduce((accum, x) => {
      accum[x.id] = x;
      return accum;
    }, {})
  );

console.log(resultWithHashMap);

普通解决方案可以像对数组的第一个元素调用 filter() 一样简单,检查 every() 后续元素是否包含 some() 个匹配的元素。

const [srcElement, ...compArray] = [...myArray];

const intersection = srcElement.filter(o => (
  compArray.every(arr => arr.some(p => p.id === o.id)))
);

console.log(intersection)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script>
const myArray = [
  [{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 3, name: 'Jake' }],
  [{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 4, name: 'Joe' }],
  [{ id: 1, name: 'Liam' }, { id: 2, name: 'Oliver' }, { id: 5, name: 'Dean' }, { id: 6, name: 'Mara' }]
]
</script>

使用嵌套 forEach 循环和 Set。遍历每个子数组并找出到目前为止的共同项。

const intersection = ([firstArr, ...restArr]) => {
  let common = new Set(firstArr.map(({ id }) => id));
  restArr.forEach((arr) => {
    const newCommon = new Set();
    arr.forEach(({ id }) => common.has(id) && newCommon.add(id));
    common = newCommon;
  });
  return firstArr.filter(({ id }) => common.has(id));
};

const myArray = [
  [
    { id: 1, name: "Liam" },
    { id: 2, name: "Oliver" },
    { id: 3, name: "Jake" },
  ],
  [
    { id: 1, name: "Liam" },
    { id: 2, name: "Oliver" },
    { id: 4, name: "Joe" },
  ],
    [
    { id: 2, name: "Oliver" },
    { id: 4, name: "Joe" },
  ],
];

console.log(intersection(myArray));