在 lodash 中用 topairs 压平嵌套对象

flatten nested object with topairs in lodash

我有一个这样的对象:

let order={
  "john":{
    "hamburger":4
  },
  "alice":{
    "pizza":10,
    "milkshake":2
  },
  "bob":{
  }
}

我想像这样展平:

let res=[
   ["john","hamburger",4],

   ["alice","pizza",4],
   ["alice","milkshake",4]

]

我知道如何使用 keyBy 反向执行此操作,但如何将它从递归对象转换为递归数组? 我尝试使用 toPairs,但我不知道如何使它递归

使用 _.toPairs() 得到一个 [name, items] 对的数组,你用 _.flatMap() 迭代它。从 items 对象中获取对,并使用 _.map() 创建包含信息的数组:

const { flatMap, toPairs, map } = _

const order = {"john":{"hamburger":4},"alice":{"pizza":10,"milkshake":2},"bob":{}}

const result = flatMap(
  toPairs(order),
  ([name, items]) => 
    map(
      toPairs(items),
      ([product, price]) => [name, product, price]
    )
)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

在原版 JS 中,您可以使用 Array.flatMap()Object.entries() 来获得相同的结果:

const order = {"john":{"hamburger":4},"alice":{"pizza":10,"milkshake":2},"bob":{}}

const result = Object
  .entries(order)
  .flatMap(([name, items]) =>
    Object.entries(items)
      .map(([product, price]) => [name, product, price])
  )

console.log(result)

此解决方案将以递归方式工作,并让您提供一个确定如何构建累加器的回调。请注意,它仅适用于对象,不适用于嵌套对象和数组的混合。

const flatten = (tree, acc, branch = [], build) =>
  Object.entries(tree).reduce(
    (a, [key, val]) =>
      typeof val !== 'object'
        ? build(a, branch, key, val)
        : flatten(val, a, branch.concat(key), build),
    acc
  );

在你的例子中,你希望分支是一个节点数组,最后一个叶子也在同一个数组中。

const source = {
  a: {
    b: {
      c: 'c'
    }
  },
  b: {
    d: {
      x: 'sdfdsgsf'
    },
    c: {
      i: 'sdf',
      f: {
        one: {
          two: {
            three: 'deep'
          }
        }
      }
    }
  }
};

const flatten = (tree, acc, branch = [], build) =>
  Object.entries(tree).reduce(
    (a, [key, val]) =>
      typeof val !== 'object'
        ? build(a, branch, key, val)
        : flatten(val, a, branch.concat(key), build),
    acc
  );
  
 console.log(
  flatten(source, [], [], (acc, branch, key, val) => [
    ...acc,
    branch.concat(key, val)
  ])
);

产出

[
  [ 'a', 'b', 'c', 'c' ],
  [ 'b', 'd', 'x', 'sdfdsgsf' ],
  [ 'b', 'c', 'i', 'sdf' ],
  [
    'b',    'c',
    'f',    'one',
    'two',  'three',
    'deep'
  ]
]

我需要将分支节点连接成一个字符串,例如

{
  'a.b.c.d': 'string',
  'x.y.z': 'foo'
}

所以我用了

flatten(source, {}, [], (acc, branch, key, val) => ({
  ...acc,
  [branch.concat(key).join('.')]: val
}))