使用递归将嵌套对象重新格式化为字符串数组



我有以下对象:

const modules = {
celebrity: {
actor: {
male: 'male',
female: 'female'
},
director: 'director'
},
movie: 'movie',
user: 'user'
};

结果,我想要一个字符串数组,如下所示:

[
"celebrity/actor/male",
"celebrity/actor/female",
"celebrity/director",
"movie",
"user"
]

我创建以下函数:

function getPathsList(node, path = '') {
let pathsList = [];
const childs = Object.entries(node);
for (const child of childs) {
if (typeof child[1] === 'string') {
path += `/${child[1]}`
pathsList.push(path)
} else {
path += `/${child[0]}`
pathsList = [...pathsList, ...getPathsList(child[1], path, pathsList)]
}
}
return pathsList;
}

但我得到了:

[
"/celebrity/actor/male", 
"/celebrity/actor/male/female",
"/celebrity/actor/director",
"/celebrity/movie",
"/celebrity/movie/user"
]

我知道路径变量应该在某处初始化,但我无法弄清楚。

您可以使用没有路径的 appraoch,但通过迭代嵌套部件对象来组装路径。

function getPathsList(node) {
const pathsList = [];
for (const [key, value] of Object.entries(node)) {
if (value && typeof value === 'object') {
pathsList.push(...getPathsList(value).map(p => `${key}/${p}`))
} else {
pathsList.push(key);
}
}
return pathsList;
}
const modules = {
celebrity: {
actor: {
male: 'male',
female: 'female'
},
director: 'director'
},
movie: 'movie',
user: 'user'
};
console.log(getPathsList(modules));

另一种方式,使用reduce

const modules = {celebrity:{actor:{male:"male",female:"female"},director:"director"},movie:"movie",user:"user"};
function getPathsList(node, path = '') {
return Object.entries(node)
.reduce(
(res, [k, v]) => res.concat(
typeof v === "string" ? `${path}${v}` : getPathsList(v, `${path}${k}/`
)
), []);
}
console.log(getPathsList(modules));

你可以考虑一个类似"dfs"的算法,在那里你可以探索从根到叶的每一条路径。

然后,使用"/"连接路径。

微妙之处:不要将叶子本身放入路径中(例如:否则你会得到电影/电影(

下面是使用平面地图的示例

const modules = {"celebrity":{"actor":{"male":"male","female":"female"},"director":"director"},"movie":"movie","user":"user"}
const flatten = x => {
if (typeof(x) === 'string') { return [[]] }
// each node has for children its entries
// each node returns an array of path
return Object.entries(x).flatMap(([k, v]) => {
return flatten(v).map(path => [k , ...path])
})
}
console.log(flatten(modules).map(path => path.join('/')))

难度在哪里?

const
modules = 
{ celebrity: 
{ actor:    { male: 'male', female: 'female' } 
, director: 'director'
} 
, movie: 'movie'
, user:  'user'
} 
, pathsList = []
;
function getPathsList( obj, path='' )
{
for (let key in obj )
{
if (typeof(obj[key]) === 'object') getPathsList( obj[key], path+'/'+key )
else pathsList.push( (path+'/'+key).substring(1) )
}
}
getPathsList( modules )

console.log( pathsList )

一个非常简单的递归解决方案,使用Object .entries返回一个数组,该数组仅包含非对象的空字符串,否则,对于每个键值,将键与对该值的递归调用的结果组合在一起。 唯一稍微棘手的部分是不要在空字符串之前插入斜杠(/(。 它看起来像这样:

const getPathsList = (obj) => Object (obj) === obj
? Object .entries (obj) .flatMap (
([k, v]) => getPathsList (v) .map (p => p ? k + '/' + p : k)
)
: ['']
const modules = {celebrity: {actor: {male: 'male', female: 'female'}, director: 'director'}, movie: 'movie', user: 'user'}
console .log (getPathsList (modules))

但我更愿意以稍微不同的方式执行此操作,在将结果收集到值数组(例如[['celebrity', 'actor', 'male'], ['celebrity', 'actor', 'female'], ... ['user']](,然后简单地用斜杠将这些新数组连接在一起。 它非常相似:

const getPaths = (obj) => Object (obj) === obj
? Object .entries (obj) .flatMap (
([k, v]) => getPaths (v) .map (p => [k, ...p])
)
: [[]]
const getPathsList = (obj) => 
getPaths (obj) .map (xs => xs .join ('/'))
const modules = {celebrity: {actor: {male: 'male', female: 'female'}, director: 'director'}, movie: 'movie', user: 'user'}
console .log (getPathsList (modules))

我发现中间数组格式更有帮助。

这是一个比我通常写的稍微不那么复杂的getPaths版本。 通常我会区分数字数组索引和字符串对象键,但这在这里无关紧要,因为我们将它们折叠回字符串,因此此版本已简化。

最新更新