javascript - 按特定属性值嵌套的对象的递归过滤数组
问题描述
这是我得到的数组,我的目的是过滤整个对象数组并返回一个具有确定名称的对象数组(即使它位于嵌套的最深层次的子对象中)。例如,如果我按“Model8”过滤,我的函数的返回值必须是 =[{ name: "Model8", type: "file", path: "/path/to/file" }]
const arr = [
{
name: "Model",
type: "directory",
path: "/path/to/folder",
children: [
{
name: "Model1",
type: "file",
path: "/path/to/file",
children: [
{
name: "Model2",
type: "file",
path: "/path/to/file",
children: [
{
name: "Model3",
type: "file",
path: "/path/to/file",
children: [
{ name: "Model4", type: "file", path: "/path/to/file" },
],
},
],
},
],
},
],
},
{
name: "Inventory",
type: "directory",
path: "/path/to/folder",
children: [{ name: "inventory.yaml", type: "file", path: "/path/to/file" }],
},
{
name: "UI",
type: "directory",
path: "/path/to/folder",
children: [
{ name: "elements", type: "directory", path: "/path/to/file" },
{ name: "viewmodel", type: "directory", path: "/path/to/file" },
{ name: "i18n", type: "directory", path: "/path/to/file" },
{
name: "index.template.html",
type: "file",
path: "/path/to/file",
children: [
{
name: "Model5",
type: "file",
path: "/path/to/file",
children: [
{
name: "Model6",
type: "file",
path: "/path/to/file",
children: [
{
name: "Model7",
type: "file",
path: "/path/to/file",
children: [
{ name: "Model8", type: "file", path: "/path/to/file" },
],
},
],
},
],
},
],
},
],
},
{ name: "DeviceConnector", type: "directory", children: [] },
];
我想出了2个选项:
1)
function searchFilter(searchVal,arr) {
const res = arr.filter(function filteredList(el) {
if (el.children) {
el.children = el.children.filter(filteredList);
}
if (el.name.toLowerCase().includes(searchVal.toLowerCase())) return true;
return res;
});
}
searchFilter("Model8",arr)
但是这里的主要问题是由于某种原因我不能“在初始化之前访问'res'”
2)
function searchFilter(arr, name) {
const searchItem = arr.find((i) => i.name === name);
if (!searchItem) {
return arr.filter((i) => searchFilter(i.children, name));
}
return searchitem;
}
在这里,我不能低于数组的第一个迭代对象。最大深度是具有“Model3”名称属性的对象。
解决方案
我们可以编写一个通用函数来收集与提供的谓词匹配的所有嵌套值,然后在它上面进行名称搜索,如下所示:
const collect = (pred) => (xs = []) =>
xs .flatMap (x => [
... (pred (x) ? [x] : []),
... collect (pred) (x .children)
])
const findByName = (target) =>
collect (({name}) => name == target)
const arr = [{name: "Model", type: "directory", path: "/path/to/folder", children: [{name: "Model1", type: "file", path: "/path/to/file", children: [{name: "Model2", type: "file", path: "/path/to/file", children: [{name: "Model3", type: "file", path: "/path/to/file", children: [{name: "Model4", type: "file", path: "/path/to/file"}]}]}]}]}, {name: "Inventory", type: "directory", path: "/path/to/folder", children: [{name: "inventory.yaml", type: "file", path: "/path/to/file"}]}, {name: "UI", type: "directory", path: "/path/to/folder", children: [{name: "elements", type: "directory", path: "/path/to/file"}, {name: "viewmodel", type: "directory", path: "/path/to/file"}, {name: "i18n", type: "directory", path: "/path/to/file"}, {name: "index.template.html", type: "file", path: "/path/to/file", children: [{name: "Model5", type: "file", path: "/path/to/file", children: [{name: "Model6", type: "file", path: "/path/to/file", children: [{name: "Model7", type: "file", path: "/path/to/file", children: [{name: "Model8", type: "file", path: "/path/to/file"}]}]}]}]}]}, {name: "DeviceConnector", type: "directory", children: []}]
console .log (findByName ('Model8') (arr))
我们可以在这里传递任何谓词。我们可以进行不区分大小写的比较,或子字符串搜索,或组合。但这与树的实际遍历无关,因此将其分离为自己的函数很有用。
如果你真的不喜欢这样称呼findByName ('Model8') (arr)
(我现在更喜欢,但有些人不喜欢),我们可以这样重写:
const findByName = (xs, target) =>
collect (({name}) => name == target) (xs)
findByName (arr, 'Model8')
如果我们愿意,我们可以更进一步,传递一个函数来决定如何找到节点的子节点。在这里我们只需要传递(x) => x .children
,但并不是我们想要使用的每个结构都必须使用这个名称"children"
。该版本留给读者作为练习。;-)
推荐阅读
- flutter - 用 Flutter Gallery 中的 Pages 替换 body 中的图标 BottomNavigationBar 示例
- swift - 如何实例化弱委托而不触发“实例将立即被释放,因为属性‘tableViewDelegate’是‘弱’”
- json - 如何使用 Gson 将如下所示的 JSON 响应转换为 POJO?
- java - Hadoop '-classpath' 未被识别为内部或外部命令、可运行程序或批处理文件
- java - 如何在 Android Studio 中对具有多个值的名称进行分组?
- google-app-engine - 使用 PHP 在 Google App Engine 上发送邮件时出错
- c++ - Visual Studio 2015 OpenCV 断言在 cv::imshow windows.cpp 中失败 (size.width>0 && size.height>0)
- html - 响应式布局,桌面移动
- vector - 向量向量的内存布局是什么?
- php - 使用 php 抓取 html 时查找内容不起作用