简体   繁体   English

如何使用ramda将平面列表转换为分层列表?

[英]How to turn flat list into hierarchical one using ramda?

Like in question. 喜欢有问题。 I would like to turn the following list into hierarchical list with children fields. 我想将以下列表转换为带有子字段的分层列表。 'parentId' can stay. “ parentId”可以保留。 I just removed it for clarity. 为了清楚起见,我只是删除了它。 The goal is to use ramda with its immutable behavior. 目标是使用具有不变行为的ramda。

const x = [
  {
    id: 1,
    parentId: null,
    name: 'Top 1'
  },
  {
    id: 2,
    parentId: 1,
    name: 'Middle'
  },
  {
    id: 3,
    parentId: 2,
    name: 'Leaf'
  },
  {
    id: 4,
    parentId: null,
    name: 'Top 2'
  },
];

into this one: 进入这个:

const result = [
    {
        id: 1,
        name: 'Top 1',
        children: [
            {
                id: 2,
                name: 'Middle',
                children: [
                    {
                        id: 3,
                        name: 'Leaf',
                        children: []
                    }
                ]
            }
        ]
    },
    {
        id: 4,
        name: 'Top 2',
        children: []
    }
];

As I answered in Gitter , this seems to do it: 正如我在Gitter中回答的那样,这似乎可以做到:

const makeTree = items => {
  const hierarchy = reduce(
    (index, item) => item.parentId in index 
      ? assoc(item.id, [], assoc(item.parentId, append(item.id, index[item.parentId]), index))
      : assoc(item.id, [], index)
    , {}, 
    items
  ) //=> E.g. {"1":[2],"2":[3],"3":[],"4":[]} 
  const index = map(head, groupBy(prop('id'), items)) //=> E.g. {"!": <item1>, "2": <item2>, ...}
  const makeNode = id => dissoc('parentId', assoc('children',  map(makeNode, hierarchy[id]), index[id]))

  return map(makeNode, pluck('id', filter(item => item.parentId == null, items)))
}

It does involve several passes through the data, and the use of groupBy here seems a bit hacky, but I think it's reasonable. 它确实涉及对数据的多次传递,并且在此处使用groupBy似乎有点groupBy ,但我认为这是合理的。

Also those nested assoc s aren't pretty. 而且那些嵌套的assoc也不漂亮。 I might refactor into compose / pipe . 我可能会重构为compose / pipe

You can see this in action on the Ramda REPL . 您可以在Ramda REPL上看到这一点。

In a pure Ramda / point-free / functional style, I would do the following: 在纯Ramda /无点/功能样式中,我将执行以下操作:

const overChildren = over(lensProp('children'))
const findChildren = completeList => parent => filter(child => child.parentId === parent.id, completeList)

const assocChildren = completeList => map(pipe(
  parent => assoc('children', findChildren(completeList)(parent), parent),
  parent => overChildren(assocChildren(completeList), parent)
))

const removeParentIds = map(pipe(
  dissoc('parentId'),
  overChildren(x => removeParentIds(x))
))

const isTop = compose(isNil, prop('parentId'))
const keepOnlyTop = filter(isTop)

const hierarchize = completeList => pipe(
  assocChildren(completeList),
  keepOnlyTop,
  removeParentIds
)(completeList)

hierarchize(list)

Try it here 在这里尝试

Note: I've focused on the readability and maintainability, not on performance. 注意:我专注于可读性和可维护性,而不是性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM