our data structure is a nested array with objects
interface dtModel {
id: number;
permission: number;
childs: dtModel[];
}
const data: dtModel[] = [
{
id: 1,
permission: 2,
childs: [
{
id: 2,
permission: 1,
childs: [
{
id: 3,
permission: 3,
childs: [],
},
],
},
],
},
{
id: 4,
permission: 1,
childs: [
{
id: 5,
permission: 2,
childs: [
{
id: 6,
permission: 3,
childs: [
{
id: 7,
permission: 1,
childs: [],
},
],
},
],
},
],
},
];
I tried with help of RxJs to create a flattened array like this which is I'm not succeeded yet
[
{id:1,permission:2},
{id:2,permission:1},
{id:3,permission:3},
{id:4,permission:1},
{id:5,permission:2},
{id:6,permission:3},
{id:7,permission:1}
]
I tried to do that with help of 'reduce' but because my childs' property does not always have the same length I couldn't do that with this approach.
of(data)
.pipe(
map((items: dtModel[]) => {
return items.reduce((res, curr) => {
res.push({ id: curr.id, permission: curr.permission });
return res;
}, []);
})
)
.subscribe(console.log);
CodePudding user response:
need to make recursion
const source = [
{
id: 1,
permission: 2,
childs: [
{
id: 2,
permission: 1,
childs: [
{
id: 3,
permission: 3,
childs: [],
},
],
},
],
},
{
id: 4,
permission: 1,
childs: [
{
id: 5,
permission: 2,
childs: [
{
id: 6,
permission: 3,
childs: [
{
id: 7,
permission: 1,
childs: [],
},
],
},
],
},
],
},
];
const result = [];
const getAllItemsPerChildren = (item) => {
result.push({ id: item.id, permission: item.permission });
if (item.childs) {
return item.childs.map((i) => getAllItemsPerChildren(i));
}
};
source.forEach((i) => getAllItemsPerChildren(i));
console.log(result)
RXJS SOLUTION
demo: https://stackblitz.com/edit/typescript-dlva1z?file=index.ts
const source$ = of({
data: [],
last: false,
check: source,
}).pipe(
expand((data) =>
data.last
? EMPTY
: of(data.check).pipe(
map((currentItem) => {
const childs = (currentItem as any).flatMap((i) => i?.childs || []);
return {
data: currentItem.map((i) => ({
id: i.id,
permissions: i.permission,
})),
last: !childs?.length,
check: childs,
};
})
)
),
reduce((acc, items) => [...acc, ...(items as any).data], [])
);
source$.subscribe((data) => console.log('result ', data));
Explanation:
- The main idea to use
expand
operator - it allow us to create recursion. - To stop recursion need to return
EMPTY
of({data: [],last: false, check: source})
- it is our storedata
is assigned to keep parsed item - that will be used in reduce operator - to concat the whole data- one return from expand equal to one emit
last
allows to control recusrion, we are checking if all items is parsedcheck
- element to parse, intial value set to your entire data
CodePudding user response:
You need to do a tree (= your data structure) traversal and for every node you have to push {id://some id,permission://some permission}
on a result array.
You don't need rxjs for that.
CodePudding user response:
A simplified expand
version, just need to ensure every item is emitted and do some clean up at the end with map
from(data)
.pipe(
expand((obj) => {
return obj.childs && obj.childs.length
? from(obj.childs)
: EMPTY;
}),
map(obj=>({ id: obj.id, permission: obj.permission })),
toArray()
)
.subscribe(console.log);