[英]How would you tackle this? using the reduce method to calculate the sum of a nested object value in this array?
[英]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.