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

时间:2017-10-09 11:44:52

标签: javascript ramda.js

有问题。我想将以下列表转换为带有子字段的分层列表。 ' parentId的'可以留。为了清楚起见,我刚删除它。目标是使用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'
  },
];

进入这一个:

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

2 个答案:

答案 0 :(得分:0)

正如我在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)))
}

确实涉及到数据的多次传递,而groupBy在这里的使用似乎有些苛刻,但我认为这是合理的。

那些嵌套的assoc也不漂亮。我可能会重构为compose / pipe

您可以在 Ramda REPL 上看到这一点。

答案 1 :(得分:0)

在纯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

注意:我专注于可读性和可维护性,而不是性能。