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)
添加回答
举报