如何将flattenObj函数从ramda cookbook转换为迭代函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将flattenObj函数从ramda cookbook转换为迭代函数相关的知识,希望对你有一定的参考价值。

我正在处理测试环境nodejs / sequelize / mocha / chai。我发现这个flattenObj在测试对象时非常有用,例如由sequelize生成。 它使这些结构易于消化,结果变得更加简洁 太糟糕了,它以递归的方式实现:(。 特别是在javascript中,这意味着厄运,因为总是存在潜伏的调用堆栈限制。 喜欢在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函数,当对象变得太复杂时,它会导致调用堆栈超出错误。 如果它也适用于更复杂的结构,这将是非常有用的。

答案

我不认为以递归方式实现它是一件坏事。这是处理递归数据结构(如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))

以上是关于如何将flattenObj函数从ramda cookbook转换为迭代函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 ramda 将数组数组转换为数组对象

带有 FP 类型的 Ramda

如何使用 Axios 将 CSRF Coo​​kie 从 React 发送到 Django Rest Framework

如何使用无点递归实现使用 Ramda 删除对象中的空值?

Ramda 可以有 isString 吗?

javascript Ramda JS最常用的函数