在javascript中检索深度嵌套的对象时不使用find两次

时间:2019-01-23 14:58:02

标签: javascript

我能够在下面的javascript中找到该对象,但是它非常可怕,并且我做了两次查找。

我会对一种更好的方法感兴趣,而这种方法不涉及我目前未使用的lodash。

const statuses = [{
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 5,
    name: 'bar'
  }]
}, {
  items: [{
    id: 1,
    name: 'mook'
  }, {
    id: 2,
    name: 'none'
  }, {
    id: 3,
    name: 'soot'
  }]
}]

const selected = statuses.find(status => {
  const none = status.items.find(alert => {
    return alert.name === 'none';
  });

  return !!none;
});

console.log(selected)

const a = selected.items.find(s => s.name === 'none');

console.log(a)

4 个答案:

答案 0 :(得分:0)

您可以将所有状态项与reduce()组合成一个数组,然后只需find()一次:

const statuses = [{
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 5,
    name: 'bar'
  }]
}, {
  items: [{
    id: 1,
    name: 'mook'
  }, {
    id: 2,
    name: 'none'
  }, {
    id: 3,
    name: 'soot'
  }]
}]

const theNones = statuses
    .reduce(function(s, t) { return s.items.concat(t.items); })
    .find(function(i) { return i.name === 'none'; });

console.log(theNones);

答案 1 :(得分:0)

您可以像这样使用嵌套的somefind。这样,一旦找到匹配项,您就可以跳过该操作。

const statuses=[{items:[{id:1,name:'foo'},{id:5,name:'bar'}]},{items:[{id:1,name:'mook'},{id:2,name:'none'},{id:3,name:'soot'}]}];

let found;

statuses.some(a => {
  const s = a.items.find(i => i.name === "none");
  
  if (s) {
    found = s;
    return true
  } else {
    return false
  }
})

console.log(found)

您可以使用mapconcatfind做类似的事情。这有点慢,但看起来更整洁。

const statuses=[{items:[{id:1,name:'foo'},{id:5,name:'bar'}]},{items:[{id:1,name:'mook'},{id:2,name:'none'},{id:3,name:'soot'}]}]

const found = [].concat(...statuses.map(a => a.items))
                .find(a => a.name === "none")

console.log(found)

这里有jsperf与您的代码进行比较。第一个是最快的。

答案 2 :(得分:0)

您可以使用tutorialflatMap

注意:Array.prototype.flatMapfind的语言,不是该语言的一部分,但在当今的大多数环境(包括Babel)中都可以使用。

var arr = [{items:[{id:1,name:'foo'},{id:5,name:'bar'}]},{items:[{id:1,name:'mook'},{id:2,name:'none'},{id:3,name:'soot'}]}]

console.log(
  arr
  .flatMap(({ items }) => items)
  .find(({
    name
  }) => name === 'none')
)

我们可以通过填充(通过map + reduce)来填充平面图:

var arr = [{items:[{id:1,name:'foo'},{id:5,name:'bar'}]},{items:[{id:1,name:'mook'},{id:2,name:'none'},{id:3,name:'soot'}]}];

console.log(
  arr
  .map(({ items }) => items)
  .reduce((items1, items2) => items1.concat(items2))
  .find(({
    name
  }) => name === 'none')
)

您还可以减少结果:

var arr = [{items:[{id:1,name:'foo'},{id:5,name:'bar'}]},{items:[{id:1,name:'mook'},{id:2,name:'none'},{id:3,name:'soot'}]}]

console.log(
  arr.reduce((result, {
      items
    }) =>
    result ? result : items.find(({
      name
    }) => name === 'none'), null)
)

答案 3 :(得分:0)

一个reduce函数(对所有内容进行一次迭代),该函数返回符合条件的任何对象的数组:

const [firstOne, ...others] = statuses.reduce((found, group) => found.concat(group.items.filter(item => item.name === 'none')), [])

由于您似乎首先对遇到的第一个想法感兴趣,因此我使用了重组方法来模仿您的find想法。由于此操作仅对每个项目进行一次迭代,因此在性能方面要比替代答案更好,但是如果您确实对性能有所关注,那么for循环是您的最佳选择,因为返回值将使函数短路并给出您的价值:

const findFirstMatchByName = (name) => {
  for (let group of statuses) {
    for (let item of group.items) {
      if (item.name === name) {
        return item
      }
    }
  }
}

findFirstMatchByName('none')