javascript - Javascript如何循环一个我们不知道里面有多少嵌套数组的json数组?
问题描述
更新的脚本
这是我正在处理的更新脚本:
function recursive(data, append_name) {
for (parent_key in data) {
var dim_type = data[parent_key]["type"];
var dim_label = "";
var dim_name = data[parent_key]["name"];
if (typeof(data[parent_key]["label"])=="object") {
dim_label = data[parent_key]["label"]["english"];
}
else {
dim_label = data[parent_key]["label"];
}
for (child_key in data[parent_key]["children"]){
//console.log(data[parent_key]["children"][child_key])
var child_label = data[parent_key]["children"][child_key]["label"]["english"];
if (append_name == "" || append_name == undefined) {
var child_name = data[parent_key]["children"][child_key]["name"];
} else {
var child_name = append_name+"/"+data[parent_key]["children"][child_key]["name"];
}
if("children" in data[parent_key]["children"][child_key]) {
recursive(data[parent_key]["children"][child_key]["children"], dim_name)
}
else {
outputArray.push({"dim_label": dim_label,
"dim_name": dim_name,
"child_name": dim_name+"/"+child_name,
"child_label": child_label})
}
console.log(outputArray, "")
}
//console.log(key, dim_label, dim_name, dim_type);
}
}
结果仅显示 6 条记录中的 3 条记录,它们仅是前 3 行。
编辑结束
原始问题
我有 JSON 文件,我需要在它上面运行一个脚本来获取 4 个主要字段:
- 暗淡标签
- 暗淡名称
- 字段标签
- 字段名
JSON数组的结构如下:
{
"name": "Info",
"title": "Info",
"default_language": "default",
"id_string": "...",
"type": "survey",
"children": [
{
"type": "text",
"name": "basic_info",
"label": "Basic Info",
"children": [
{
"type": "text",
"name": "name",
"label": {
"english": "What is your name"
}
},
{
"type": "text",
"name": "address",
"label": {
"english": "What is your address?"
}
}
]
},
{
"type": "text",
"name": "more_data",
"label": "More Data",
"children": [
{
"type": "text",
"name": "favourite_food",
"label": {
"english": "What is your favourite food?"
}
},
{
"type": "text",
"name": "favourite_destination",
"label": {
"english": "What is your favourite destination?"
},
"children": [
{
"type": "text",
"name": "france",
"label": {
"english": "France"
},
"type": "text",
"name": "usa",
"label": {
"english": "USA"
}
}
]
}
]
},
{
"type": "number",
"name": "estimated_income",
"label": "What is your annual estimated income?"
}
]
}
所需的输出应如下所示:
请注意,最后一条记录的字段相似,因为里面没有子数组。
请注意,对于 favourite_destination 部分,在另一个数组中有一个子数组,这就是为什么最后有以下字段:
more_data/favourite_destination/法国
more_data/favourite_destination/美国
所以最后的 field_name 将保存其父名称的完整路径。
我试过这个 JavaScript 脚本:
function recursive(arr, dim_label, dim_name){
for (prop in arr) {
var title = arr["title"];
if (prop == "children") {
for (child in arr[prop]){
var dim_name = "";
var dim_label = "";
var field_name = "";
var field_label = "";
dim_name = arr[prop][child]["name"] +"/"+dim_name;
type = arr[prop][child]["type"];
field_name = dim_name+arr[prop][child]["name"];
dim_label =arr[prop][child]["name"]["english"];
field_label = "";
if ("label" in arr[prop][child] ) {
dim_label = arr[prop][child]["label"]["english"];
field_label = arr[prop][child]["label"]["english"]
}
else {
dim_label = dim_name;
}
array.push({label: dim_label, name: dim_name});
/* if (type != "calculate" && type != "select one") {
if ("children" in arr[prop][child]) {
recursive(arr[prop][child], dim_label, dim_name);
}
} */
console.log(dim_name, dim_label, field_name, field_label)
}
}
}
}
结果只有 3 条记录:
“basic_info/”,未定义,“basic_info/basic_info”,未定义
“更多数据/”,未定义,“更多数据/更多数据”,未定义
“estimated_income/”,未定义,“estimated_income/estimated_income”,未定义
这是一个jsfiddle。
如何遍历一个我不知道里面有多少嵌套数组的数组来获取所需的信息?
解决方案
这是一种将数据遍历与输出格式分开的方法:
const getPaths = (obj) =>
obj .children
? obj .children .flatMap (getPaths) .map (p => [obj, ...p])
: [[obj]]
const extract = (data) =>
getPaths (data) .map ((path) => ((
field = path [path .length - 1],
parent = path .length > 2 ? path [path .length - 2] : path [path .length - 1]
) => ({
dim_label: parent .label .english || parent .label,
dim_name: path .slice (1, path .length > 2 ? -1 : Infinity) .map (n => n.name) .join('/'),
field_label: field .label .english || field .label,
field_name: path .slice(1) .map (n => n .name) .join('/')
}))())
const data = {name: "Info", title: "Info", default_language: "default", id_string: "...", type: "survey", children: [{type: "text", name: "basic_info", label: "Basic Info", children: [{type: "text", name: "name", label: {english: "What is your name"}}, {type: "text", name: "address", label: {english: "What is your address?"}}]}, {type: "text", name: "more_data", label: "More Data", children: [{type: "text", name: "favourite_food", label: {english: "What is your favourite food?"}}, {type: "text", name: "favourite_destination", label: {english: "What is your favourite destination?"}, children: [{type: "text", name: "france", label: {english: "France"}}, {type: "text", name: "usa", label: {english: "USA"}}]}]}, {type: "number", name: "estimated_income", label: "What is your annual estimated income?"}]}
console .log (extract (data))
const display = (objs) => `<table><thead><tr>${Object.keys(objs[0]).map(k => `<th>${k}</th>`).join('')}</tr></thead><tbody>${objs.map(o => `<tr>${Object.values(o).map(v => `<td>${v}</td>`).join('')}</tr>`).join('')}</tbody></table>`
document.getElementById('output').innerHTML = display (extract (data))
.as-console-wrapper {max-height: 50% !important; bottom: 0}
table {border-collapse: collapse}
td, th { border: 1px solid #ccc}
th {background: #eee}
<div id="output"></div>
getPaths
将这样的嵌套对象转换为路径数组,每个路径都是沿子树向下的对象列表,以在叶节点处结束,此处定义为没有children
属性的对象。
我们的主要函数,extract
调用getPaths
并将结果路径映射到对象中,方法是找到最后两个节点作为我们的field
和parent
( dim
?) 对象,从这些节点和整个路径中提取相关数据到新对象中。
我们通过记录此对象列表并调用display
将数据转换为 HTML 表的函数来演示这一点。
请注意,输出字段定义中的复杂性说明您的数据中存在一些严重的不一致。如果它不存在,我们需要检查something. label .english
并默认为。something .label
当我们列出路径时,我们需要忽略最外层的容器。我们需要对只有一个节点和最外层容器的路径进行奇怪的处理。如果您对该数据格式有任何控制权,我建议进行一些清理是值得的。
更新
用户Thankyou 指出,如果我们使用call
函数而不是上面的IIFE,这可能会更简单一些。
这个版本,使用相同的getPaths
功能,应该同样好用:
const call = (fn, ...args) =>
fn (...args)
const extract = (data) =>
getPaths (data) .map ((path) => call ((
field = path [path .length - 1],
parent = path .length > 2 ? path [path .length - 2] : path [path .length - 1]
) => ({
dim_label: parent .label .english || parent .label,
dim_name: path .slice (1, path .length > 2 ? -1 : Infinity) .map (n => n.name) .join('/'),
field_label: field .label .english || field .label,
field_name: path .slice(1) .map (n => n .name) .join('/')
})))
也可以这样写:
const extract = (data) =>
getPaths (data) .map (
(path) => call
((field, parent) => ({
dim_label: parent .label .english || parent .label,
dim_name: path .slice (1, path .length > 2 ? -1 : Infinity) .map (n => n.name) .join('/'),
field_label: field .label .english || field .label,
field_name: path .slice(1) .map (n => n .name) .join('/')
}),
path [path .length - 1],
path .length > 2 ? path [path .length - 2] : path [path .length - 1]
))
推荐阅读
- firebase - Flutter Firebase Mlkit 是否需要 Firebase 项目?
- java - 将带有 if 条件的嵌套 for 循环转换为 Java 8
- react-native - 滑动到列表末尾时不调用 FlatList `onEndReached` 回调
- php - 检查用户出生日期为 18 岁或以上的功能并不总是正常工作
- ruby-on-rails - 当我运行完整的 rspec 测试套件时,Spring 是否可以工作?
- python - 即使我不按侧键,我的宇宙飞船也会继续移动
- wix - WiX 捆绑包在同一版本的 ARP 中创建多个条目
- vue.js - nuxt 匿名中间件,如何在组件上设置数据
- reactjs - 尝试访问 JWT Authenticated Users 内容在 laravel 中给出 401
- django - 如何以角度将json api数据加载到html模板?