使用父对象值将路径添加到嵌套对象的递归函数
Recursive function to add path to nested object using parent object values
我正在尝试使用其祖先的属性向所有嵌套对象添加“路径”。本质上,我想使用其父对象的属性值的串联而不是使用键(就像我可以使用点符号、lodash 等)来表示嵌套对象的层次结构的“路径”。
我尝试过的:
interface SimpleObject {
name : string
slug : string
slug_path? : string
fields? : SimpleObject[]
}
const addNestedObjSlug = (data:SimpleObject[], parents:SimpleObject[] = []) => {
data.map((obj) => {
obj.slug_path = parents.length > 0 ? `${parents.map(({slug}) => slug).join('.')}.${obj.slug}` : obj.slug
if(obj.fields && obj.fields.length > 0) {
parents.push(obj)
// I think the issue is here, that I probably need to set parents to an empty array at some point
return addNestedObjSlug(obj.fields, parents)
}
})
return data
}
const desiredResult = addNestedObjSlug([
{
name : 'Item 1',
slug : 'i1',
fields : [
{
name : 'Item 1 - 1',
slug : 'i1-1'
},
{
name : 'Item 1 - 2',
slug : 'i1-2'
},
{
name : 'Item 1 - 3',
slug : 'i1-3'
}
]
},
{
name : 'Item 2',
slug : 'i2',
fields : [
{
name : 'Item 2 - 1',
slug : 'i2-1',
fields : [
{
name : 'Item 2 - 1 - 1',
slug : 'i2-1-1'
}
]
}
]
}
])
我的预期结果是:
[
{
"name": "Item 1",
"slug": "i1",
"fields": [
{
"name": "Item 1 - 1",
"slug": "i1-1",
"slug_path": "i1.i1-1"
},
{
"name": "Item 1 - 2",
"slug": "i1-2",
"slug_path": "i1.i1-2"
},
{
"name": "Item 1 - 3",
"slug": "i1-3",
"slug_path": "i1.i1-3"
}
],
"slug_path": "i1"
},
{
"name": "Item 2",
"slug": "i2",
"fields": [
{
"name": "Item 2 - 1",
"slug": "i2-1",
"fields": [
{
"name": "Item 2 - 1 - 1",
"slug": "i2-1-1",
"slug_path": "i2.i2-1.i2-1-1"
}
],
"slug_path": "i2.i2-1"
}
],
"slug_path": "i2"
}
]
但我得到以下结果,其中原始嵌套对象的 slug 是非祖先对象的新 slug_path 属性的一部分。
[
{
"name": "Item 1",
"slug": "i1",
"fields": [
{
"name": "Item 1 - 1",
"slug": "i1-1",
"slug_path": "i1.i1-1" // correct
},
{
"name": "Item 1 - 2",
"slug": "i1-2",
"slug_path": "i1.i1-2" // correct
},
{
"name": "Item 1 - 3",
"slug": "i1-3",
"slug_path": "i1.i1-3" // correct
}
],
"slug_path": "i1" // correct
},
{
"name": "Item 2",
"slug": "i2",
"fields": [
{
"name": "Item 2 - 1",
"slug": "i2-1",
"fields": [
{
"name": "Item 2 - 1 - 1",
"slug": "i2-1-1",
"slug_path": "i1.i2.i2-1.i2-1-1" // incorrect
}
],
"slug_path": "i1.i2.i2-1" // incorrect
}
],
"slug_path": "i1.i2" // incorrect
}
]
你可以关闭路径。
const
add = p => o => {
const
slug_path = p + (p && '.') + o.slug,
fields = (o.fields || []).map(add(slug_path));
return { ...o, slug_path, ...(fields.length ? { fields } : {}) };
},
addNestedObjSlug = array => array.map(add(''));
console.log(addNestedObjSlug([{ name: 'Item 1', slug: 'i1', fields: [{ name: 'Item 1 - 1', slug: 'i1-1' }, { name: 'Item 1 - 2', slug: 'i1-2' }, { name: 'Item 1 - 3', slug: 'i1-3' }] }, { name: 'Item 2', slug: 'i2', fields: [{ name: 'Item 2 - 1', slug: 'i2-1', fields: [{ name: 'Item 2 - 1 - 1', slug: 'i2-1-1' }] }] }]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
如果您不介意也将 slugPath 添加到您的根元素(我个人认为在任何情况下这对于一致性更好),那么应该这样做:
const addSlugPath = (items, path = []) =>
items .map (({slug, fields, ...rest}, _, __, newPath = [...path, slug]) => ({
... rest,
slug,
slugPath: newPath .join ('.'),
... (fields ? {fields: addSlugPath (fields, newPath)} : {})
}))
const input = [{name: "Item 1", slug: "i1", fields: [{name: "Item 1 - 1", slug: "i1-1"}, {name: "Item 1 - 2", slug: "i1-2"}, {name: "Item 1 - 3", slug: "i1-3"}]}, {name: "Item 2", slug: "i2", fields: [{name: "Item 2 - 1", slug: "i2-1", fields: [{name: "Item 2 - 1 - 1", slug: "i2-1-1"}]}]}]
console .log (addSlugPath (input))
.as-console-wrapper {max-height: 100% !important; top: 0}
请注意,我们不会在此处更改任何输入数据,而只是 return 适当添加了 slugPath 的副本。
我们在 path
中保留一个节点数组,并在每个递归级别添加到它。 _
和 __
参数只是为了覆盖 map
提供给回调函数的索引和完整数组。
我正在尝试使用其祖先的属性向所有嵌套对象添加“路径”。本质上,我想使用其父对象的属性值的串联而不是使用键(就像我可以使用点符号、lodash 等)来表示嵌套对象的层次结构的“路径”。
我尝试过的:
interface SimpleObject {
name : string
slug : string
slug_path? : string
fields? : SimpleObject[]
}
const addNestedObjSlug = (data:SimpleObject[], parents:SimpleObject[] = []) => {
data.map((obj) => {
obj.slug_path = parents.length > 0 ? `${parents.map(({slug}) => slug).join('.')}.${obj.slug}` : obj.slug
if(obj.fields && obj.fields.length > 0) {
parents.push(obj)
// I think the issue is here, that I probably need to set parents to an empty array at some point
return addNestedObjSlug(obj.fields, parents)
}
})
return data
}
const desiredResult = addNestedObjSlug([
{
name : 'Item 1',
slug : 'i1',
fields : [
{
name : 'Item 1 - 1',
slug : 'i1-1'
},
{
name : 'Item 1 - 2',
slug : 'i1-2'
},
{
name : 'Item 1 - 3',
slug : 'i1-3'
}
]
},
{
name : 'Item 2',
slug : 'i2',
fields : [
{
name : 'Item 2 - 1',
slug : 'i2-1',
fields : [
{
name : 'Item 2 - 1 - 1',
slug : 'i2-1-1'
}
]
}
]
}
])
我的预期结果是:
[
{
"name": "Item 1",
"slug": "i1",
"fields": [
{
"name": "Item 1 - 1",
"slug": "i1-1",
"slug_path": "i1.i1-1"
},
{
"name": "Item 1 - 2",
"slug": "i1-2",
"slug_path": "i1.i1-2"
},
{
"name": "Item 1 - 3",
"slug": "i1-3",
"slug_path": "i1.i1-3"
}
],
"slug_path": "i1"
},
{
"name": "Item 2",
"slug": "i2",
"fields": [
{
"name": "Item 2 - 1",
"slug": "i2-1",
"fields": [
{
"name": "Item 2 - 1 - 1",
"slug": "i2-1-1",
"slug_path": "i2.i2-1.i2-1-1"
}
],
"slug_path": "i2.i2-1"
}
],
"slug_path": "i2"
}
]
但我得到以下结果,其中原始嵌套对象的 slug 是非祖先对象的新 slug_path 属性的一部分。
[
{
"name": "Item 1",
"slug": "i1",
"fields": [
{
"name": "Item 1 - 1",
"slug": "i1-1",
"slug_path": "i1.i1-1" // correct
},
{
"name": "Item 1 - 2",
"slug": "i1-2",
"slug_path": "i1.i1-2" // correct
},
{
"name": "Item 1 - 3",
"slug": "i1-3",
"slug_path": "i1.i1-3" // correct
}
],
"slug_path": "i1" // correct
},
{
"name": "Item 2",
"slug": "i2",
"fields": [
{
"name": "Item 2 - 1",
"slug": "i2-1",
"fields": [
{
"name": "Item 2 - 1 - 1",
"slug": "i2-1-1",
"slug_path": "i1.i2.i2-1.i2-1-1" // incorrect
}
],
"slug_path": "i1.i2.i2-1" // incorrect
}
],
"slug_path": "i1.i2" // incorrect
}
]
你可以关闭路径。
const
add = p => o => {
const
slug_path = p + (p && '.') + o.slug,
fields = (o.fields || []).map(add(slug_path));
return { ...o, slug_path, ...(fields.length ? { fields } : {}) };
},
addNestedObjSlug = array => array.map(add(''));
console.log(addNestedObjSlug([{ name: 'Item 1', slug: 'i1', fields: [{ name: 'Item 1 - 1', slug: 'i1-1' }, { name: 'Item 1 - 2', slug: 'i1-2' }, { name: 'Item 1 - 3', slug: 'i1-3' }] }, { name: 'Item 2', slug: 'i2', fields: [{ name: 'Item 2 - 1', slug: 'i2-1', fields: [{ name: 'Item 2 - 1 - 1', slug: 'i2-1-1' }] }] }]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
如果您不介意也将 slugPath 添加到您的根元素(我个人认为在任何情况下这对于一致性更好),那么应该这样做:
const addSlugPath = (items, path = []) =>
items .map (({slug, fields, ...rest}, _, __, newPath = [...path, slug]) => ({
... rest,
slug,
slugPath: newPath .join ('.'),
... (fields ? {fields: addSlugPath (fields, newPath)} : {})
}))
const input = [{name: "Item 1", slug: "i1", fields: [{name: "Item 1 - 1", slug: "i1-1"}, {name: "Item 1 - 2", slug: "i1-2"}, {name: "Item 1 - 3", slug: "i1-3"}]}, {name: "Item 2", slug: "i2", fields: [{name: "Item 2 - 1", slug: "i2-1", fields: [{name: "Item 2 - 1 - 1", slug: "i2-1-1"}]}]}]
console .log (addSlugPath (input))
.as-console-wrapper {max-height: 100% !important; top: 0}
请注意,我们不会在此处更改任何输入数据,而只是 return 适当添加了 slugPath 的副本。
我们在 path
中保留一个节点数组,并在每个递归级别添加到它。 _
和 __
参数只是为了覆盖 map
提供给回调函数的索引和完整数组。