我正在处理一个测试环境nodejs / sequelize / mocha / chai。
我发现这个flattenObj非常有用
测试对象时,例如由sequelize生成。
它使这些结构可用于蔡,并且结果变得更简洁
不幸的是,它是以递归的方式实现的:(。
,尤其是在Java脚本中,它总是注定要失败,因为总是存在调用堆栈限制。
像将递归函数包装在setTimeout中这样的技巧似乎对我不起作用,而且很难看。
我目前正在尝试以迭代方式重写它,但这至少对我来说是个难题。
在ramda函数中处理while循环感觉不对。
有没有一种方法可以在不破坏ramda约定的情况下以调用堆栈友好的方式进行此操作?
const go = obj_ => chain(([k, v]) => {
if (type(v) === 'Object' || type(v) === 'Array') {
return pipe(
tap(console.log),
map(([k_, v_]) => [`${k}.${k_}`, v_])
)(go(v))
} else {
return [[k, v]]
}
}, toPairs(obj_))
const flattenObj = obj => {
return fromPairs(go(obj))
}
flattenObj({a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}})
{
"a": 1,
"b.c": 3,
"d.e.f": 6,
"d.g.0.h": 8,
"d.g.0.i": 9,
"d.g.1": 0
}
这可以按预期工作,但由于递归go函数,当对象变得过于复杂时,它会崩溃,导致调用堆栈超出错误。
如果它也适用于更复杂的结构,则将非常有用。
答案 0 :(得分:1)
我认为以递归方式实现它不是一件坏事。这是处理诸如JS对象之类的递归数据结构的最佳方法。
但是,如果您要管理自己的堆栈,则始终可以将递归解决方案转换为迭代解决方案。这是一个相当丑陋的方法,但似乎适用于该简单测试用例:
const flattenObj = (obj) => {
const results = [];
const steps = Object.entries(obj)
while (steps.length) {
const [key, val] = steps.splice(0, 1)[0]
if (typeof val == 'object') {
Array.prototype.push.apply(steps, Object.entries(val).map(
([k, v]) => [key + '.' + k, v]
))
} else {
results.push([key, val])
}
}
return results.reduce((a, [k, v]) => ({...a, [k]: v}), {})
}
const foo = {a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}}
console.log(flattenObj(foo))
这不适用于周期性结构,但可能是菜谱版本也没有。
我最初使用Ramda函数(toPairs
代替Object.entries
,is(Object, val)
代替typeof val == 'object'
和return fromPairs(results)
代替{{ 1}}。)但是所有的突变都在继续(return results.reduce(...)
和splice
),这感觉是一种非常不合理的解决方案,我删除了它们。 (您知道,Ramda函数不希望与gauche可变性相关联!)
我不知道这是否可以解决您的问题。尽管我可以在测试中看到该实用程序,但我仅使用push
几次。但是令我震惊的是,如果这引起了递归问题,那么循环数据结构比实际深度更可能是问题。但是我当然不知道您的数据,谁知道呢?