Reputation: 2357
Let's say I have a typical tree data structure that looks like this:
[
{
att1: 'asdasd',
att2: 42,
att3: true,
subs: [ ...other objects... ]
},
...other objects...
]
It can have any shape and number of nodes, but every node has these three attributes (which have of course different values for each node).
Now, I'd like to create a new tree that would have the exact same hierarchy, but it should hold the data let's say in a format like this:
[
{
data: { att1: 'asdasd', att2: 42, att3: true },
subs: [ ...other objects... ]
},
...other objects...
]
( One way of implementing this would be to write a recursive function that visits every node of the original tree, creates the data
attribute for each one, fills up its content by the three attributes att1
, att2
and att3
, then removes these attributes of the node. This way I would have this new tree. But I don't want to change the original tree, so this is not an option for me. I also don't want to clone the tree using JSON.parse(JSON.stringify())
or in some other way and then perform the same procedure described above for this new tree. )
Instead, I'm looking for a method to generate this new tree node by node, as I'm reading the original tree node by node.
A method I can already write that visits every node of the original tree:
public copyTree(originalTree: Array<object>): Array<object> {
const newTree: Array<object> = [];
function f(subtree: Array<object>): void {
for (const node of subtree) {
// Missing here: Somehow add the current node to newTree
if (node['subs'].length > 0) f(node['subs']);
}
}
f(originalTree);
return newTree;
}
How could I complete this method (or you can show me a different implementation too) to generate the new tree?
Upvotes: 0
Views: 2213
Reputation: 33496
You can do that using the Array.prototype.map
function and recursion:
public copyTree(originalTree: Array<object>): Array<object> {
return originalTree.map(({ subs, ...data }: any) => ({
data,
subs: this.copyTree(subs)
}));
}
Upvotes: 2
Reputation: 7542
If you start by defining interfaces for your input and output shapes, you can use them and any resulting TypeScript errors to help guide you:
interface Attributes {
att1: string;
att2: number;
att3: boolean;
}
type InputNode = Attributes & {
subs: InputNode[];
}
interface OutputNode {
data: Attributes;
subs: OutputNode[];
}
Once we have those, we can set up our function definition as
function copyTree(originalTree: InputNode[]): OutputNode[] {
And then you can use rest/spread to help transfer everything around:
function copyTree(originalTree: InputNode[]): OutputNode[] {
return originalTree.map(input => {
const {
subs,
...data
} = input;
return {
subs: copyTree(subs),
data,
};
});
}
Upvotes: 2
Reputation: 18302
Well, I'd do it using map
and the spread/rest operators:
const array = [...];
const copy = array.map(item => {
const {att1, att2, att3, ...rest} = item;
return { data: {att1, att2, att3}, ...rest };
});
In this function, rest
will hold all the properties in the object except att1
, att2
, att3
. When creating the new object, adding ...rest
adds the other properties to the resulting object, so, if you have:
{
att1: '1',
att2: '2',
att3: '3',
subs: [...],
other: 'other'
}
you'd end with objects like this:
{
data: {att1: '1', att2: '2', att3: '3'},
subs: [...],
other: 'other'
}
Upvotes: 1