javascript - 如何使用 vue/javascript 通过多个属性过滤深度嵌套的 json
问题描述
我有一些具有以下结构的 JSON:
{
"root": {
"Europe": {
"children": [
{
"name": "Germany"
},
{
"name": "England",
"children": [
{
"name": "London",
"search_words": ["city", "capital"],
"children": [
{
"name": "Westminster",
"search_words": ["borough"]
}
]
},
{
"name": "Manchester",
"search_words": ["city"]
}
]
},
{
"name": "France",
"children": [
{
"name": "Paris",
"search_words": ["city", "capital"]
}
]
}
]
},
"North America": {
"children": [
{
"name": "Canada",
"children": [
{
"name": "Toronto"
},
{
"name": "Ottawa"
}
]
},
{
"name": "United States"
}
]
}
}
}
我想根据文本搜索过滤 JSON。我应该能够同时搜索 thename
和 any search_words
。最后一个问题是 JSON 可以任意深,因此它需要能够搜索所有级别。
我还需要循环并打印出 HTML 中的 JSON(使用 Vue),并根据搜索进行更新。目前尚不清楚如何在不知道 JSON 将进入多少级别的情况下做到这一点?
任何帮助将不胜感激!
解决方案
我最近回答了一个类似的问题。我在这里分享它是因为我认为它为这篇文章提供了相关的基础。不过,在开始之前,我们必须首先解决输入数据的不规则形状 -
const data2 =
{ name:"root"
, children:
Array.from
( Object.entries(data.root)
, ([ country, _ ]) =>
Object.assign({ name:country }, _)
)
}
console.log(JSON.stringify(data2, null, 2))
现在我们可以看到data2
是一个统一的{ name, children: [ ... ]}
形状——
{
"name": "root",
"children": [
{
"name": "Europe",
"children": [
{ "name": "Germany" },
{
"name": "England",
"children": [
{
"name": "London",
"search_words": [ "city", "capital" ],
"children": [
{
"name": "Westminster",
"search_words": [ "borough" ]
}
]
},
{
"name": "Manchester",
"search_words": [ "city" ]
}
]
},
{
"name": "France",
"children": [
{
"name": "Paris",
"search_words": [ "city", "capital" ]
}
]
}
]
},
{
"name": "North America",
"children": [
{
"name": "Canada",
"children": [
{ "name": "Toronto" },
{ "name": "Ottawa" }
]
},
{ "name": "United States" }
]
}
]
}
现在我们编写一个通用的深度优先遍历函数,dft
-
function* dft (t, path = [])
{ for (const _ of t.children ?? [])
yield* dft(_, [...path, t.name ])
yield [path, t]
}
我们的dft
函数为我们的输入树中的path
每个元素, -e
t
["root","Europe"]
{"name":"Germany"}
["root","Europe","England","London"]
{name:"Westminster", search_words:["borough"]}
["root","Europe","England"]
{name:"London", search_words:["city","capital"], children:[...]}
["root","Europe","England"]
{name:"Manchester", search_words:["city"]}
["root","Europe"]
{name:"England", children:[...]}
["root","Europe","France"]
{name:"Paris", search_words:["city","capital"]}
["root","Europe"]
{name:"France", children:[...]}
["root"]
{name:"Europe", children:[...]}
["root","North America","Canada"]
{name:"Toronto"}
现在我们知道每个节点的路径,我们可以创建一个index
使用 thepath
和 anysearch_words
链接回节点的路径 -
const index = t =>
Array.from
( dft(t)
, ([path, e]) =>
[ [...path, e.name, ...e.search_words ?? [] ] // all words to link to e
, e // e
]
)
.reduce
( (m, [ words, e ]) =>
insertAll(m, words, e) // update the index using generic helper
, new Map
)
这取决于通用助手insertAll
-
const insertAll = (m, keys, value) =>
keys.reduce
( (m, k) =>
m.set(k, [ ...m.get(k) ?? [], value ])
, m
)
完成后,index
我们可以为任何搜索词创建快速查找 -
const myIndex =
index(data2)
console.log(myIndex)
Map
{ "Europe" =>
[{"name":"Germany"},{"name":"Westminster",...},{"name":"London",...},{"name":"Manchester",...},{"name":"England"...},{"name":"Manchester",...}]},{"name":"Paris",...},{"name":"France"...},{"name":"Europe"...},{"name":"Manchester",...}]},{"name":"France"...}]}]
, "Germany" =>
[{"name":"Germany"}]
, "England" =>
[{"name":"Westminster",...},{"name":"London",...},{"name":"Manchester",...},{"name":"England"...},{"name":"Manchester",...}]}]
, "London" =>
[{"name":"Westminster",...},{"name":"London",...}]
, "Westminster" =>
[{"name":"Westminster",...}]
, "borough" =>
[{"name":"Westminster",...}]
, "city" =>
[{"name":"London",...},{"name":"Manchester",...},{"name":"Paris",...}]
, "capital" =>
[{"name":"London",...},{"name":"Paris",...}]
, "Manchester" =>
[{"name":"Manchester",...}]
, "France" =>
[{"name":"Paris",...},{"name":"France"...}]
, "Paris" =>
[{"name":"Paris",...}]
, "North America" =>
[{"name":"Toronto"},{"name":"Ottawa"},{"name":"Canada"...},{"name":"United States"},{"name":"North America"...},
{"name":"United States"}]}]
, "Canada" =>
[{"name":"Toronto"},{"name":"Ottawa"},{"name":"Canada"...}]
, "Toronto" =>
[{"name":"Toronto"}]
, "Ottawa" =>
[{"name":"Ottawa"}]
, "United States" =>
[{"name":"United States"}]
}
这应该突出显示数据中剩余的不一致之处。例如,您有一些节点嵌套在city
、capital
或下borough
。还值得注意的是,我们可能应该s.toLowerCase()
在所有索引键上使用,以便查找可以不区分大小写。这是留给读者的练习。
创建index
很容易,您只需要做一次-
const myIndex =
index(data2)
您的索引可以根据需要重复用于尽可能多的查找 -
console.log(myIndex.get("Toronto") ?? [])
console.log(myIndex.get("France") ?? [])
console.log(myIndex.get("Paris") ?? [])
console.log(myIndex.get("Canada") ?? [])
console.log(myIndex.get("Zorp") ?? [])
[{"name":"Toronto"}]
[{"name":"Paris",...},{"name":"France"...}]
[{"name":"Paris",...}]
[{"name":"Toronto"},{"name":"Ottawa"},{"name":"Canada"...}]
[]
在你的 Vue 应用程序中插入结果是留给你的。
推荐阅读
- excel - 使用单元格地址获取命令按钮
- html - 表单后 ModelAttribute 为空
- google-cloud-platform - 谷歌云端点不支持文件
- python - 编写一个与python中的min方法功能相同的程序
- javascript - Vue 测试 - 模拟 axios 返回未定义
- python-3.x - 有没有办法在 tkinter scrolledtext 小部件中获取当前指针位置
- rsync - 如何将具有更新文件的远程文件夹与也更新的本地文件夹同步?
- python - 为 Python 中的列表取消堆叠制作一个衬里代码
- java - Java MessageFormat 无法格式化特定字符串
- python - Python,为什么我们可以创建在类创建中没有定义的类变量?