javascript - 使用 map reduce 等,你如何在嵌套数组中找到符合特定条件的第一个项目,并在找到后停止?

标签 javascript arrays multidimensional-array find

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

在一维数组中,这就是 Array.find 函数的用途,但是对于二维数组,甚至更整洁的 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 ),但同样,这似乎更像是遍历整棵树,而不是在找到特定节点后停止并返回。

有人愿意挑战吗? ;)

最佳答案

最简单(虽然有点难看)的解决方案是在找到匹配的 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));

关于javascript - 使用 map reduce 等,你如何在嵌套数组中找到符合特定条件的第一个项目,并在找到后停止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54470142/

相关文章:

javascript - 如何在没有 id 的情况下将 jQuery 元素传递给 JavaScript 函数?

javascript - php以轮播方式显示文件夹中的所有图像

java - 如何将数字转换为ascii值或字符并存储在字符串数组中

c - 在struct中需要一个 "variable"大小的二维数组

ruby-on-rails - 如何在 Ruby 中将数组的数组从字符串转换为 float ?

c++ - 我可以创建一个可以复制任意大小的二维数组的 'CopyArray' 函数吗?

javascript - 在内部文本之前插入子元素

javascript - 至少选择了一个选择选项的表单验证被选中

python - numpy.concatenate 多维数组

arrays - JSTL <c :set> body content exact specification