Найти объект внутри массива внутри другого массива


let bigArray = [
{
    Name: 'Trump',
    children: [
                 {Name: 'TrumpChild1', City: 'city1'}, 
                 {Name: 'TrumpChild2', City: 'city2'}
    ]
},
{
    Name: 'Barack Obama',
    children: [
                 {Name: 'Barack Obama Child1', City: 'city3'}, 
                 {Name: 'Barack Obama Child2', City: 'city4'}
    ]
},
{
    Name: 'Clinton',
    children: [
                 {Name: 'Clinton Child 1', City: 'city5'}, 
                 {Name: 'Clinton Child2', City: 'city6'}
    ]
},

]

Я хочу найти объект из массива внутри другого массива

bigArray.find(b => b.children.find(c=>c.City === 'city1'))

Приведенный выше код возвращает массив father

bigArray.forEach(b => b.children.find(c=>c.City === 'city1'))

И это возвращение неопределенное

Как лучше всего вернуть искомый объект ?

3   3   2018-05-17 02:49:05

3 ответа:

Вы можете сначала расплющить этот массив до массива внутренних объектов, а затем использовать filter() или find().

let bigArray = [
  {
      Name: 'Trump',
      children: [
                   {Name: 'TrumpChild1', City: 'city1'}, 
                   {Name: 'TrumpChild2', City: 'city2'}
      ]
  },
  {
      Name: 'Barack Obama',
      children: [
                   {Name: 'Barack Obama Child1', City: 'city3'}, 
                   {Name: 'Barack Obama Child2', City: 'city4'}
      ]
  },
  {
      Name: 'Clinton',
      children: [
                   {Name: 'Clinton Child 1', City: 'city5'}, 
                   {Name: 'Clinton Child2', City: 'city6'}
      ]
  }
];

let all = bigArray.reduce((prev, next) => prev.concat(next.children), []);
let result = all.find(obj => obj.City === 'city1');
console.log(result);

// if there can be multiple matches then use filter
let results = all.filter(obj => obj.City === 'city1');
console.log(results);

Дети могут родиться в одном городе и так далее.find() не особенно хорошо подходит для этой задачи, так как он возвращает только первый результат, который ищет. В этом случае filter() это та функция, которая нам нужна.

Ниже мы называем filter внутри reduce(). Это отличается от другого ответа, так как он не повторяется через ваши входные данные более одного раза. Другой ответ сначала создаст целый массив потомков, а затем во второй итерации, выберите те, которые соответствуют вашему запросу города.

Альтернативно, этот ответ повторяется через каждого президента один раз и добавляет любые соответствующие дети к результату по пути.

const findByCity = (city, data = {}) =>
  data .reduce
    ( (result, { children = [] }) =>
        result .concat (children .filter (c => c.city === city))
    , []
    )

В ваших входных данных каждый ребенок имеет уникальный город, поэтому он не дает хорошей демонстрации. Я добавил еще несколько детей, рожденных в city5, так что мы можем увидеть ответ, который включает в себя несколько детей

const data =
  [ { name: 'Trump'
    , children:
        [ { name: 'Trump Child 1', city: 'city1' }
        , { name: 'Trump Child 2', city: 'city2' }
        ]
    }
  , { name: 'Barack Obama'
    , children:
        [ { name: 'Barack Obama Child 1', city: 'city3' }
        , { name: 'Barack Obama Child 2', city: 'city4' }
        ]
    }
  , { name: 'Clinton'
    , children:
        [ { name: 'Clinton Child 1', city: 'city5' }
        , { name: 'Clinton Child 2', city: 'city6' }
        ]
    }
  , { name: 'Bush'
    , children:
        [ { name: 'Bush Child 1', city: 'city5' }
        , { name: 'Bush Child 2', city: 'city5' }
        ]
    }
  ]

console .log (findByCity ('city1', data))
// [ { name: 'Trump Child 1', city: 'city1' } ]

console .log (findByCity ('city5', data))
// [ { name: 'Clinton Child 1', city: 'city5' }
// , { name: 'Bush Child 1', city: 'city5' }
// , { name: 'Bush Child 2', city: 'city5' }
// ]

Другой ответ, приведенный здесь, сломался бы, если бы ваши данные содержали президента без children. findByCity не страдает от этой проблемы

const data =
  [ // ...
  , { name: 'Bush'
    , children:
        [ { name: 'Bush Child 1', city: 'city5' }
        , { name: 'Bush Child 2', city: 'city5' }
        ]
    }

  // watch out for child-less presidents!
  , { name: 'Polk' }
  ]

Разверните программу ниже, чтобы запустить ее в вашем браузере

const findByCity = (city, data = {}) =>
  data .reduce
    ( (result, { children = [] }) =>
        result .concat (children .filter (c => c.city === city))
    , []
    )

const data =
  [ { name: 'Trump'
    , children:
        [ { name: 'Trump Child 1', city: 'city1' }
        , { name: 'Trump Child 2', city: 'city2' }
        ]
    }
  , { name: 'Barack Obama'
    , children:
        [ { name: 'Barack Obama Child 1', city: 'city3' }
        , { name: 'Barack Obama Child 2', city: 'city4' }
        ]
    }
  , { name: 'Clinton'
    , children:
        [ { name: 'Clinton Child 1', city: 'city5' }
        , { name: 'Clinton Child 2', city: 'city6' }
        ]
    }
  , { name: 'Bush'
    , children:
        [ { name: 'Bush Child 1', city: 'city5' }
        , { name: 'Bush Child 2', city: 'city5' }
        ]
    }
  , { name: 'Polk' }
  ]

console .log (findByCity ('city1', data))
// [ { name: 'Trump Child 1', city: 'city1' } ]
    
console .log (findByCity ('city5', data))
// [ { name: 'Clinton Child 1', city: 'city5' }
// , { name: 'Bush Child 1', city: 'city5' }
// , { name: 'Bush Child 2', city: 'city5' }
// ]

Вы также можете сделать это без выравнивания массива.

let matches = [];

// using array.forEach(), plus && in .map() to shorten the comparison syntax
bigArray.forEach(obj => {obj.children.map(c => c.City == 'city1' &&  matches.push(c))});

// and this version works even if there is not a `children` property
bigArray.forEach(obj => {obj.children && obj.children.map(c => c.City == 'city1' &&  matches.push(c))});