首页 > 解决方案 > 使用 map reduce 等,您将如何在嵌套数组中找到符合特定条件的第一项,并在找到后停止?

问题描述

您如何在嵌套数组中找到符合特定条件的第一项,并在找到后停止?

在 1D 数组中,这就是 Array.find 函数的用途,但是对于 2D 数组,甚至更简洁的 n 维数组,您将如何做呢?

此外,我正在尝试使用 es6 和数组函数(例如 find、map、reduce 等)提出一个简洁的解决方案,而不是使用更传统的循环和变量来维护状态(请参阅下面的一个这样的老式解决方案)。

数据可能看起来像这样

const data = [
  {arr: [{val:6,name:'aaa'},{val:4,name:'bbb'},{val:8,name:'ccc'}]},
  {arr: [{val:3,name:'mmm'},{val:5,name:'nnn'},{val:9,name:'ppp'},{val:5,name:'ooo'}]}
]

我希望我可以做一些类似于array.find(及其谓词/测试功能)的事情,但我需要更深入地找到例如val = 5的第一个项目。对于上面的数据,我希望获得名称为“nnn”(不是“ooo”)的项目,并在找到第一个项目后结束流程。与 Array.find 类似,我想避免在找到匹配项后处理其余数据。

一种无聊的旧方法是这样的,带有一个循环,但这……很无聊,而且不像可爱的数组函数那么整洁:)

let found
// loop through all data entries in the outer array
for (const d of data) {
  // attempt to find a matching item in the inner array.
  // using array.find means we stop at the first match, yay!
  const theItem = d.arr.find(item => {
    return myPredicate(item)
  })
  // we also need to break out of the loop. ugh!
  if (theItem) {
    found = theItem
    break
  }
}
// return what we found (may be undefined)
return found

现在,我意识到我可以用 find() 和 some() 做一些事情,比如说,类似于这里的答案ES6 - Finding data in nested arrays,但问题是在外部数组上使用 find 意味着我们得到了外部数据数组的第一项,而我想要内部 arr 数组中的一项。

const outer = data.find(d => {
  return d.arr.some(item => {
    return myPredicate(item)
  })
})

然后我将不得不再次处理外部以在 outer.arr 中找到项目,例如

outer.arr.find(item => myPredicate(item))

这不适合我,因为对 some(...) 的调用已经通过并找到了匹配的内部项目!

我认为这将是直截了当的,也许是这样,但出于某种原因,我陷入了这个小挑战。

我还查看了不错的遍历库(https://www.npmjs.com/package/traverse),但这似乎更多是关于遍历整个树,而不是在找到特定节点后停止并返回.

有人来挑战吗?;)

标签: javascriptarraysmultidimensional-arrayfind

解决方案


最简单(虽然有点难看)的解决方案是在找到时将匹配分配给item外部变量:

let foundNested;
data.some(subarr => (
  subarr.some((item) => {
    if (myPredicate(item)) {
      foundNested = item;
      return true;
    }
  });
});

您可以.reduce用来避免分配给外部变量:

const myPredicate = ({ val }) => val === 5;
const data = [
  {arr: [{val:6,name:'aaa'},{val:4,name:'bbb'},{val:8,name:'ccc'}]},
  {arr: [{val:3,name:'mmm'},{val:5,name:'nnn'},{val:9,name:'ppp'},{val:5,name:'ooo'}]}
];

const found = data.reduce((a, { arr }) => (
  a ||
  arr.find(myPredicate)
), null);
console.log(found);

问题是,reduce不会短路 - 无论如何它都会完全迭代外部数组。对于真正的短路,我想我更喜欢使用for..of循环:

const data = [
  {arr: [{val:6,name:'aaa'},{val:4,name:'bbb'},{val:8,name:'ccc'}]},
  {arr: [{val:3,name:'mmm'},{val:5,name:'nnn'},{val:9,name:'ppp'},{val:5,name:'ooo'}]}
];
function findNested(outerArr, myPredicate) {
  for (const { arr } of outerArr) {
    for (const item of arr) {
      if (myPredicate(item)) {
        return item;
      }
    }
  }
}

const myPredicate = ({ val }) => val === 5;
console.log(findNested(data, myPredicate));


推荐阅读