Используя уменьшение карты и т. Д., Как бы вы нашли первый элемент, соответствующий определенным критериям во вложенном массиве, и остановились, когда нашли? - PullRequest
0 голосов
/ 01 февраля 2019

Как бы вы нашли первый элемент, соответствующий определенным критериям во вложенном массиве, и остановились, когда его нашли?

В одномерном массиве для этого предназначена функция Array.find, но как бы вы это сделали?сделать это для двумерного массива, и даже точнее, для массива n-размерности?

Кроме того, я пытаюсь найти точное решение, используя es6 и функции массива, такие как поиск, отображение, уменьшение и т. д.вместо того, чтобы использовать более традиционные циклы и переменные для поддержания состояния (см. одно из таких решений старой школы ниже).

Данные могут выглядеть примерно так

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 - Поиск данных во вложенных массивах , но проблема в том, что использование поиска во внешнем массиве означает, что мы получаем первый элемент внешнего массива данных, тогда как я хочу получить элемент из внутреннего массива arr.

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

Затем мне нужно было бы обработать внешний ОПЯТЬ, чтобы найти элемент в outer.arr, что-то вроде

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

Это не устраивает меня, как призыв к некоторым (...) уже прошел и нашел соответствующий внутренний предмет!

Я думал, что это будет прямо вперед, и, возможно, так и есть, но по той или иной причине я застрял в этом небольшом испытании.

Я тоже смотрелХорошая библиотека прохождения (https://www.npmjs.com/package/traverse),, но опять же, похоже, больше о прохождении через целое дерево, чем об остановке и возврате после обнаружения определенного узла.

Кто-нибудь готов к испытанию?;)

Ответы [ 4 ]

0 голосов
/ 01 февраля 2019

Это похоже на работу, но, на мой взгляд, она все еще не чиста с той переменной 'found', которая находится вне основного блока и назначается изнутри вложенного блока find.Хотя лучше.Мысли?

let found
data.find(d =>
  d.arr.find(item => {
    found = myPredicate(item) ? item : void 0
    return found !== void 0
  }) !== void 0
)
return found
0 голосов
/ 01 февраля 2019

Вы захотите написать свою собственную find функцию, которая не принимает предикат, а производит обратный вызов:

function find(iterable, callback) {
    for (const value of iterable) {
        const result = callback(value);
        if (result !== undefined)
            return result;
    }
}

С этим вы можете написать

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'}]}
];
console.log(find(data, ({arr}) => find(arr, o => o.val == 5 ? o : undefined)));

В качестве альтернативы, если вы хотите получить все результаты, flatMap - идеальный инструмент:

data.flatMap(({arr}) => arr.filter(({val}) => val == 5));
0 голосов
/ 01 февраля 2019

Конечно, почему бы и нет.Я готов к этому.Это, вероятно, может быть улучшено.Но это будет работать.Допустим, вы пытаетесь найти объект с идентификатором 5 в многомерном массиве.

  const arr = [[[{id: 1}], [{id: 2}]], [[{id: 3}]], [[{id: 4}], [{id: 5}], [{id: 6}]]]
  function findObject (obj) {
    if (Array.isArray(obj)) {
      const len = obj.length
      for (let i = 0; i < len; i++) {
        const found = findObject(obj[i])
        if (found) {
          return found
        }
      }
    } else if (obj.id === 5) { // Put your search condition here.
      return obj
    }
  }

  const obj = findObject(arr)
  console.log('obj: ', obj)
0 голосов
/ 01 февраля 2019

Самым простым (хотя и несколько уродливым) решением было бы присвоить совпадающее 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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...