Skip to content

Instantly share code, notes, and snippets.

@alinnert
Last active June 30, 2021 09:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alinnert/614da8ebdefa653e006a053a97196f9f to your computer and use it in GitHub Desktop.
Save alinnert/614da8ebdefa653e006a053a97196f9f to your computer and use it in GitHub Desktop.
A function that flattens a tree structure while preserving nesting information
const { map, flatMapDeep, add, flow } = require('lodash/fp')
const data = [
{
id: 1,
type: 'group',
name: 'Colors',
items: [
{ id: 2, type: 'item', name: 'Red' },
{ id: 3, type: 'item', name: 'Purple' },
{ id: 4, type: 'item', name: 'Black' }
]
},
{
id: 5,
type: 'group',
name: 'Food',
items: [
{ id: 6, type: 'item', name: 'Cheese' },
{ id: 7, type: 'item', name: 'Potatoes' },
{ id: 10,
type: 'group',
name: 'Sandwich',
items: [
{ id: 11, type: 'item', name: 'Bread' },
{ id: 12, type: 'item', name: 'Cheese' },
{ id: 13, type: 'item', name: 'Salami' }
] }
]
},
{ id: 8, type: 'item', name: 'Kitten' },
{
id: 14,
type: 'group',
name: 'Matryoshka A',
items: [
{
id: 15,
type: 'group',
name: 'Matryoshka B',
items: [
{
id: 16,
type: 'group',
name: 'Matryoshka C',
items: [
{
id: 17,
type: 'group',
name: 'Matryoshka D',
items: [
{
id: 18,
type: 'item',
name: 'Secret Treasure'
}
]
}
]
}
]
}
]
},
{ id: 9, type: 'item', name: 'Rainbow' },
{
id: 19,
type: 'group',
name: 'Box',
items: [
{
id: 20,
type: 'group',
name: 'Box in a box (which is empty)',
items: []
}
]
}
]
const increment = add(1)
const levelizeIterator = childrenProperty => levelProperty => function iterateLevel (level = 0) {
return item => {
item[levelProperty] = level
if (item.hasOwnProperty(childrenProperty)) {
const step = flow(increment, iterateLevel, flatMapDeep)
const nextLevel = step(level)
const children = nextLevel(item[childrenProperty])
delete item[childrenProperty]
return [item, children]
}
return item
}
}
// The children of a node are stored in a property named `items`
// The level information will be stored in a property named `level`
const itemsLevelizer = levelizeIterator('items')('level')
// The `level` property is mainly used interlally. You can set it to whatever you need.
// It defaults to 0
const rootItemsLevelizer = itemsLevelizer()
const levelizeTree = flatMapDeep(rootItemsLevelizer)
const dataFlat = levelizeTree(data)
const logJSON = flow(JSON.stringify, console.log)
logJSON(dataFlat)
const stringifyItem = item => `${' '.repeat(item.level)}[${item.id}] ${item.name} ${item.type === 'group' ? '(+)' : ''}`
const logItem = flow(stringifyItem, console.log)
const logItems = map(logItem)
logItems(dataFlat)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment