2 回答

TA貢獻1829條經驗 獲得超9個贊
這看起來會做到這一點:
const filterDeep = (pred) => (xs, kids) =>
xs .flatMap (
x =>
pred (x)
? [x]
: (kids = filterDeep (pred) (x .children || [])) && kids.length
? [{... x, children: kids}]
: []
)
const testIncludes = (condition) => (obj) =>
Object .entries (condition) .every (
([k, v]) => (obj [k] || '') .toLowerCase () .includes (v .toLowerCase ())
)
const filterMatches = (obj, conditions) =>
filterDeep (testIncludes (conditions)) (obj)
const input = [{label: "Home", key: "home", level: 1, children: [{label: "Indoor Furniture", key: "furniture", level: 2, children: [{label: "Chair", key: "chair", level: 3}, {label: "Table", key: "table", level: 3}, {label: "Lamp", key: "lamp", level: 3}]}]}, {label: "Outdoor", key: "outdoor", level: 1, children: [{label: "Outdoor Furniture", key: "furniture", level: 2, children: [{label: "Trampoline", key: "trampoline", level: 3}, {label: "Swing", key: "swing", level: 3}, {label: "Large sofa", key: "large sofa", level: 3}, {label: "Medium Sofa", key: "mediumSofa", level: 3}, {label: "Small Sofa Wooden", key: "smallSofaWooden", level: 3}]}, {label: "Games", key: "games", level: 2, children: []}]}, {label: "Refurbrished Items", key: "refurbrished items", level: 1, children: []}, {label: "Indoor", key: "indoor", level: 1, children: [{label: "Electicity", key: "electicity", level: 2, children: []}, {label: "Living Room Sofa", key: "livingRoomSofa", level: 2, children: []}]}]
console .log ('sofa:', filterMatches (input, {label: 'sofa'}))
console .log ('furniture:', filterMatches (input, {label: 'furniture'}))
.as-console-wrapper {max-height: 100% !important; top: 0}
我們分離出遞歸過濾機制以及對象匹配部分,將它們重新放在一起filterMatches。這個想法是,我們可能想通過多種方式進行過濾,因此該函數采用可以測試當前節點的任意謂詞函數。testIncludes接受一個鍵值對對象并返回一個函數,該函數接受一個對象并報告該對象的相應鍵是否均包含相關值。(我根據您的輸入/請求的輸出組合在此處添加了不區分大小寫的檢查。)
請注意,我用單詞filter而不是 來命名中心函數find,因為find通常意味著返回第一個匹配項,而filter應該返回所有匹配項。
為了我自己的使用,我會稍微不同地構造 main 函數:
const filterMatches = (conditions) => (obj) =>
filterDeep (testIncludes (conditions)) (obj)
console .log ('sofa:', filterMatches ({label: 'sofa'}) (input))
我非常喜歡這些柯里化函數,并且按照這個順序的參數,我覺得它們是最有用的。但是YMMV。
更新
評論指出主要功能出現 lint 故障。這是可以理解的,因為這在條件表達式內使用賦值時做了一些棘手的事情。所以這里有一些工作變體:
將分配移至默認參數:
const filterDeep = (pred) => (xs, kids) =>
xs .flatMap (
(x, _, __, kids = filterDeep (pred) (x .children || [])) =>
pred (x)
? [x]
: kids.length
? [{... x, children: kids}]
: []
)
優點:
這使我們的僅表達風格保持活力,并避免了上述的棘手問題。
很容易閱讀
缺點:
它使用默認參數,這有其問題。
flatMat它需要從(Here_和__.)中命名兩個未使用的參數
使用聲明樣式:
const filterDeep = (pred) => (xs, kids) =>
xs .flatMap ((x) => {
if (pred (x)) {
return [x]
}
const kids = filterDeep (pred) (x .children || [])
if (kids.length > 0) {
return [{... x, children: kids}]
}
return []
})
優點:
不再有任何形式的棘手
更適合初學者
缺點:
if與使用純表達式相比, and returnare語句和語句導致的模塊化代碼較少。
使用call輔助函數:
const call = (fn, ...args) => fn (...args)
const filterDeep = (pred) => (xs, kids) =>
xs .flatMap (
(x) =>
pred (x)
? [x]
: call (
(kids) => kids.length ? [{... x, children: kids}] : [],
filterDeep (pred) (x .children || [])
)
)
優點:
輔助函數call非常有用,并且可以在很多地方重用。
它避免了任何參數的擺弄
缺點:
這將真正的三部分測試(returning [x]、returning[{... x, children: kids}]和returning [])的最后兩個子句合并到一個函數中
我對最后一個版本有一點偏好。但他們中的任何一個都可以。

TA貢獻1813條經驗 獲得超2個贊
也許這就足夠了:
const findTerm = (arr, term) => arr.filter(e => JSON.stringify(e).indexOf(term) >= 0)
添加回答
舉報