我有一个对象数组,每个对象都有一个id作为键。每个对象代表ID的导航列表。
我需要将所有导航列表合并到一个大列表中,其中的叶子包含所属的ID。
结果对象应该不包含任何数组,但叶子将是ID的列表。
我已经尝试过递归解决方案,像合并和分配之类的lodash函数,但是我对对象的深度感到困惑
输入的JSON例如:
[
{
"id0": [
{
"Topitem 1": [
{
"Subitem 1": [
"Leaf 1"
]
}, {
"Subitem 2": [
"Leaf 2"
]
}
]
},
{
"Topitem 1": [
{
"Subitem 3": [
"Leaf 1"
]
}
]
},
{
"Topitem 2": [
"Leaf 1",
"Leaf 3"
]
},
{
"Topitem 3": [
{
"Subitem 1": [
{
"SubSubitem 1": [
"Leaf 4"
]
}
]
}
]
}
]
},
{
"id1": [
"Leaf 5"
]
},
{
"id2": [
"Leaf 5"
]
},
{
"id3": [
{
"Topitem 1": [
"Leaf 1",
{
"Subitem 2": [
"Leaf 2",
"Leaf 3"
]
}
]
}, {
"Topitem 2": [
"Leaf 1",
"Leaf 2"
]
}
]
},
{
"id4": [
"Leaf 5"
]
}
]
预期输出为:
{
"Topitem 1": {
"Subitem 1": {
"Leaf 1": ["id0"]
},
"Subitem 2": {
"Leaf 2": ["id0","id3"],
"Leaf 3": ["id3"]
},
"Subitem 3": {
"Leaf 1": ["id0"]
},
"Leaf 1": ["id3"]
},
"Topitem 2": {
"Leaf 1": ["id0","id3"],
"Leaf 2": ["id0","id3"]
},
"Topitem 3": {
"Subitem 1": {
"SubSubitem 1": {
"Leaf 4": ["id0"]
}
}
},
"Leaf5": ["id1","id2","id4"]
}
答案 0 :(得分:1)
您可以采用一种迭代和递归的方法,即在第一次运行时使用一个不同的函数,即保存id
以供以后在数组中收集,然后对嵌套的对象/键使用递归部分。 / p>
给定数据结构的主要问题是,最后,数组包含字符串而不是对象。
function convert(array) {
function iter(array, object, value) {
array.forEach(o => {
if (!o || typeof o !== 'object') {
(object[o] = object[o] || []).push(value);
return;
}
Object
.entries(o)
.forEach(([k, v]) => iter(v, object[k] = object[k] || {}, value));
});
}
var result = {};
array.forEach(o => Object.entries(o).forEach(([k, v]) => iter(v, result, k)));
return result;
}
var data = [{ id0: [{ "Topitem 1": [{ "Subitem 1": ["Leaf 1"] }, { "Subitem 2": ["Leaf 2"] }] }, { "Topitem 1": [{ "Subitem 3": ["Leaf 1"] }] }, { "Topitem 2": ["Leaf 1", "Leaf 3"] }, { "Topitem 3": [{ "Subitem 1": [{ "SubSubitem 1": ["Leaf 4"] }] }] }] }, { id1: ["Leaf 5"] }, { id2: ["Leaf 5"] }, { id3: [{ "Topitem 1": ["Leaf 1", { "Subitem 2": ["Leaf 2", "Leaf 3"] }] }, { "Topitem 2": ["Leaf 1", "Leaf 2"] }] }, { id4: ["Leaf 5"] }];
console.log(convert(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:0)
这是使用 lodash 和 object-scan 的解决方案。此解决方案无需递归
// const objectScan = require('object-scan');
// const lodash = require('lodash');
const myObject = [{ id0: [{ 'Topitem 1': [{ 'Subitem 1': ['Leaf 1'] }, { 'Subitem 2': ['Leaf 2'] }] }, { 'Topitem 1': [{ 'Subitem 3': ['Leaf 1'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 3'] }, { 'Topitem 3': [{ 'Subitem 1': [{ 'SubSubitem 1': ['Leaf 4'] }] }] }] }, { id1: ['Leaf 5'] }, { id2: ['Leaf 5'] }, { id3: [{ 'Topitem 1': ['Leaf 1', { 'Subitem 2': ['Leaf 2', 'Leaf 3'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 2'] }] }, { id4: ['Leaf 5'] }];
const convert = (obj) => objectScan(['**'], {
filterFn: ({ key, value, context }) => {
if (typeof value !== 'string') {
return;
}
const k = [...key.slice(2).filter((e) => typeof e === 'string'), value];
const cur = lodash.get(context, k);
if (cur === undefined) {
lodash.set(context, k, [key[1]]);
} else {
cur.push(key[1]);
}
}
})(obj, {});
console.log(convert(myObject));
// => { 'Leaf 5': [ 'id4', 'id2', 'id1' ], 'Topitem 2': { 'Leaf 2': [ 'id3' ], 'Leaf 1': [ 'id3', 'id0' ], 'Leaf 3': [ 'id0' ] }, 'Topitem 1': { 'Subitem 2': { 'Leaf 3': [ 'id3' ], 'Leaf 2': [ 'id3', 'id0' ] }, 'Leaf 1': [ 'id3' ], 'Subitem 3': { 'Leaf 1': [ 'id0' ] }, 'Subitem 1': { 'Leaf 1': [ 'id0' ] } }, 'Topitem 3': { 'Subitem 1': { 'SubSubitem 1': { 'Leaf 4': [ 'id0' ] } } } }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>
<script src="https://bundle.run/lodash@4.17.20"></script>
免责声明:我是object-scan
的作者这里有一个解决方案,我们可以跟踪堆栈,从而避免使用 lodash。不幸的是,它并不像我希望的那样优雅
// const objectScan = require('object-scan');
const myObject = [{ id0: [{ 'Topitem 1': [{ 'Subitem 1': ['Leaf 1'] }, { 'Subitem 2': ['Leaf 2'] }] }, { 'Topitem 1': [{ 'Subitem 3': ['Leaf 1'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 3'] }, { 'Topitem 3': [{ 'Subitem 1': [{ 'SubSubitem 1': ['Leaf 4'] }] }] }] }, { id1: ['Leaf 5'] }, { id2: ['Leaf 5'] }, { id3: [{ 'Topitem 1': ['Leaf 1', { 'Subitem 2': ['Leaf 2', 'Leaf 3'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 2'] }] }, { id4: ['Leaf 5'] }];
const convert = (obj) => objectScan(['[*]*.**[*]', '[*]*.**.*'], {
breakFn: ({
matchedBy, key, value, property, context
}) => {
if (matchedBy.includes('[*]*.**.*')) {
const cur = context[context.length - 1];
if (!(property in cur)) {
cur[property] = {};
}
context.push(cur[property]);
} else if (typeof value === 'string') {
const cur = context[context.length - 1];
if (!(value in cur)) {
cur[value] = [];
}
cur[value].push(key[1]);
}
},
filterFn: ({ matchedBy, context }) => {
if (matchedBy.includes('[*]*.**.*')) {
context.pop();
}
}
})(obj, [{}])[0];
console.log(convert(myObject));
// => { 'Leaf 5': [ 'id4', 'id2', 'id1' ], 'Topitem 2': { 'Leaf 2': [ 'id3' ], 'Leaf 1': [ 'id3', 'id0' ], 'Leaf 3': [ 'id0' ] }, 'Topitem 1': { 'Subitem 2': { 'Leaf 3': [ 'id3' ], 'Leaf 2': [ 'id3', 'id0' ] }, 'Leaf 1': [ 'id3' ], 'Subitem 3': { 'Leaf 1': [ 'id0' ] }, 'Subitem 1': { 'Leaf 1': [ 'id0' ] } }, 'Topitem 3': { 'Subitem 1': { 'SubSubitem 1': { 'Leaf 4': [ 'id0' ] } } } }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>
免责声明:我是object-scan
的作者