簡體   English   中英

使用map reduce等,如何在嵌套數組中找到匹配特定條件的第一項,並在找到后停止?

[英]Using map reduce etc, how would you find the first item matching a certain criteria in a nested array, and stop once found?

您如何在嵌套數組中找到匹配特定條件的第一項,並在找到后停止?

在1D數組中,這就是Array.find函數的作用,但是對於2D數組,甚至對於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-在嵌套數組中查找數據 ,但是問題是,在外部數組上使用find意味着我們取回了外部數據數組的第一項,而我想要內部arr數組的項。

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

然后,我將不得不處理外部AGAIN才能在external.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)); 

您將要編寫自己的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));

當然可以,為什么不呢。 我願意。 這可能可以改進。 但這會起作用。 假設您正在嘗試在多維數組中找到ID為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)

這似乎可行,但我認為,將“找到”變量放在主塊外部並從嵌套的find塊內部進行分配仍然不干凈。 更好。 思考?

let found
data.find(d =>
  d.arr.find(item => {
    found = myPredicate(item) ? item : void 0
    return found !== void 0
  }) !== void 0
)
return found

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM