This question already has answers here:
Tree structure to flat array Javascript
(2 answers)
Closed 12 months ago.
I want to get length of multidimentionnal array in JS :
This is my array :
const treeData = [
{
title: '0-0',
key: '0-0',
children: [
{
title: '0-0-0',
key: '0-0-0',
children: [
{
title: '0-0-0-0',
key: '0-0-0-0',
},
{
title: '0-0-0-1',
key: '0-0-0-1',
},
{
title: '0-0-0-2',
key: '0-0-0-2',
},
],
},
{
title: '0-0-1',
key: '0-0-1',
children: [
{
title: '0-0-1-0',
key: '0-0-1-0',
},
{
title: '0-0-1-1',
key: '0-0-1-1',
},
{
title: '0-0-1-2',
key: '0-0-1-2',
},
],
},
{
title: '0-0-2',
key: '0-0-2',
},
],
},
{
title: '0-1',
key: '0-1',
children: [
{
title: '0-1-0-0',
key: '0-1-0-0',
},
{
title: '0-1-0-1',
key: '0-1-0-1',
},
{
title: '0-1-0-2',
key: '0-1-0-2',
},
],
},
{
title: '0-2',
key: '0-2',
},
];
The output should be : 15
The idea is to map trough all elements and if they have an array child, get the lentgh of it
I'm sure that I will go for a récursive function but it seems to be tricky..
I did'nt found any solutions in internet, have you an idea please ?
Thank you
function getLengthOfTreeData(treeData) {
let size = { size: 0 }; // object because it needs to be passed by reference
return getSize(size, treeData).size;
}
function getSize(size, treeData) { // recursive function
if (treeData.length === 0) {
return size;
}
size.size += treeData.length;
for (let i = 0; i < treeData.length; i++) {
const data = treeData[i];
if (data.children) getSize(size, data.children);
}
return size;
}
console.log(getLengthOfTreeData(treeData));
Related
I working on a react project using Antd and I want to be able to disable cheking childs of my Tree component, so I can check only parent.This is my code
I found that I can add checkable : false to my child but I must create a function that render me a new TreeData that I can use instead of my normal data so I've tried this :
const TreeData = (data) => {
data.map((category) => {
category.children.map((family) => {
family.children.map((table) => {
table.checkable = false;
});
});
});
};
But it return undefined when i'm console.log the data received..
So my question is : how to switch from this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
title: "0-1-0-0",
key: "0-1-0-0"
},
{
title: "0-1-0-1",
key: "0-1-0-1"
},
{
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
To this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
checkable: false,
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
checkable: false,
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
checkable: false,
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
checkable: false,
title: "0-1-0-0",
key: "0-1-0-0"
},
{
checkable: false,
title: "0-1-0-1",
key: "0-1-0-1"
},
{
checkable: false,
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
Without hardchanging the first data of my Tree.
Thank you
This may be one possible implementation to set checkable as false for the specific nodes described in this question:
const makeUnCheckable = dataArr => (
dataArr.map(
obj => ({
...obj,
children: obj?.children?.map(cObj => ({
...cObj,
checkable: false
}))
})
)
);
return (
<Tree
checkable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onCheck={onCheck}
checkedKeys={checkedKeys}
onSelect={onSelect}
selectedKeys={selectedKeys}
treeData={makeUnCheckable(treeData)}
/>
);
This is the result displayed on Codesandbox:
NOTES:
The elements showing as checked are clicked manually.
There is no check option for nodes 0-0-0, 0-0-1, 0-0-2, 0-1-0-0, 0-1-0-1, 0-1-0-2 - which is the expected objective defined in the question under To this
EDITED:
On perusing this previous question it seems like OP requires something like this:
(A tree where leaf nodes are uncheckable)
This may be achieved by a recursive method - something like this:
(Changes are present in: Lines 100 to 106. And line 118.)
EDITED - 2
Update based on comments below.
In order to identify the children for any given parent/key, something like the below may be useful:
Two methods are here. One is findKey which is recursive and gets the object which has a particular key (say 0-0-1). The other is to check if the object with the key has any children and if yes, return the children array.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed last year.
Improve this question
I have this array with two object, and I have another array with these IDs: [9054,9021,9040,8941,8947]. I want to filter the big array and get a new array with only matched IDs on the second array.
The problem is to get the same configuration of the array, I want just to delete the unmatched IDs. Any idea how to solve it?
const data =
[ { key: 9054, title: '22', children:
[ { key: 8959, title: 'ABR_ADRESSE', idFather: 8959, tableIsFamily: false, children: [] }
, { key: 8943, title: 'ABR_CONTACT', idFather: 8943, tableIsFamily: false, children: [] }
, { key: 9021, title: 'ABR_POSTE', idFather: 9021, tableIsFamily: false, children: [] }
, { key: 8969, title: 'ABR_SOCIETE', idFather: 8969, tableIsFamily: false, children: [] }
] }
, { key: 9040, title: '33', children:
[ { key: 8957, title: 'THB_Adresse_Famille', idFather: 8957, tableIsFamily: false, children: [] }
, { key: 8941, title: 'THB_Contact_Famille', idFather: 8941, tableIsFamily: false, children:
[ { key: 8947, title: 'THB_Contact_Table', idFather: 8941 }
, { key: 9855, title: 'THB_Contact_Table_BIS', idFather: 8941 }
] }
, { key: 8949, title: 'THB_Societe_Famille', idFather: 8949, tableIsFamily: false, children: [] }
, { key: 8983, title: 'THB_TELEPHONE', idFather: 8983, tableIsFamily: false, children: [] }
, { key: 10070, title: 'THB_TEST_5708', idFather: 10070, tableIsFamily: false, children: [] }
] } ]
The expected Output should be :
const data =
[ { key: 9054, title: '22', children:
[
, { key: 9021, title: 'ABR_POSTE', idFather: 9021, tableIsFamily: false, children: [] }
] }
, { key: 9040, title: '33', children:
[
, { key: 8941, title: 'THB_Contact_Famille', idFather: 8941, tableIsFamily: false, children:
[ { key: 8947, title: 'THB_Contact_Table', idFather: 8941 }
] }
] } ]
Is this your expected output?
[
{"key": 9054,"title": "22","children": [
{"key": 9021,"title": "ABR_POSTE","idFather": 9021,"tableIsFamily": false,"children": []}
]},
{"key": 9040,"title": "33","children": [
{"key": 8941,"title": "THB_Contact_Famille","idFather": 8941,"tableIsFamily": false,"children": [
{"key": 8947,"title": "THB_Contact_Table","idFather": 8941}
]}
]}
]
You will need to loop over each child and recursively filter the children and check if the sub-child key exists within the keys array.
const
data = [
{"key":9054,"title":"22","children":[
{"key":8959,"title":"ABR_ADRESSE","idFather":8959,"tableIsFamily":false,"children":[]},
{"key":8943,"title":"ABR_CONTACT","idFather":8943,"tableIsFamily":false,"children":[]},
{"key":9021,"title":"ABR_POSTE","idFather":9021,"tableIsFamily":false,"children":[]},
{"key":8969,"title":"ABR_SOCIETE","idFather":8969,"tableIsFamily":false,"children":[]}]},
{"key":9040,"title":"33","children":[
{"key":8957,"title":"THB_Adresse_Famille","idFather":8957,"tableIsFamily":false,"children":[]},
{"key":8941,"title":"THB_Contact_Famille","idFather":8941,"tableIsFamily":false,"children":[
{"key":8947,"title":"THB_Contact_Table","idFather":8941},
{"key":9855,"title":"THB_Contact_Table_BIS","idFather":8941}
]},
{"key":8949,"title":"THB_Societe_Famille","idFather":8949,"tableIsFamily":false,"children":[]},
{"key":8983,"title":"THB_TELEPHONE","idFather":8983,"tableIsFamily":false,"children":[]},
{"key":10070,"title":"THB_TEST_5708","idFather":10070,"tableIsFamily":false,"children":[]}
]}
];
// Based on: https://stackoverflow.com/a/41312330/1762224
// For an in-place delete, see: https://stackoverflow.com/a/41312346/1762224
const filterTreeList = (data, opts) =>
data.filter(item => {
if (item[opts.childrenKey]) {
item[opts.childrenKey] = filterTreeList(item[opts.childrenKey], opts);
}
return opts.keys.includes(item[opts.itemKey]);
});
const result = filterTreeList(data, {
itemKey: 'key',
childrenKey: 'children',
keys: [9054, 9021, 9040, 8941, 8947]
});
console.log(result);
.as-console-wrapper { top: 0; max-height: 100% !important; }
This question already has answers here:
Generify transformation of hierarchical array into a flat array
(2 answers)
Closed 3 years ago.
I have variable rawData like this:
let rawData = [
{
title: '1',
result: '1',
child: [
{
title: '1-1',
result: '1-1',
child: [
{
title: '1-1-1',
result: '1-1-1',
child: [
{
title: '1-1-1-1',
result: '1-1-1-1',
child: [
{
title: '1-1-1-1-1',
result: '1-1-1-1-1',
},
],
},
{
title: '1-1-1-2',
result: '1-1-1-2',
},
{
title: '1-1-1-3',
result: '1-1-1-3',
},
],
},
],
},
],
},
];
and with my function. it runs as expected, here's my function:
let normalizeArray = [];
function test(array) {
for (const key in array) {
if (array.hasOwnProperty(key)) {
const element = array[key];
if (element.hasOwnProperty('child')) {
test(element.child);
delete element.child;
normalizeArray.unshift(Object.assign({}, element));
} else {
normalizeArray.push(Object.assign({}, element));
}
}
}
}
and return (expected):
[
{ title: '1', result: '1' },
{ title: '1-1', result: '1-1' },
{ title: '1-1-1', result: '1-1-1' },
{ title: '1-1-1-1', result: '1-1-1-1' },
{ title: '1-1-1-1-1', result: '1-1-1-1-1' },
{ title: '1-1-1-2', result: '1-1-1-2' },
{ title: '1-1-1-3', result: '1-1-1-3' },
];
But, if the rawData like this:
let rawData = [
{
title: '1',
result: '1',
child: [
{
title: '1-1',
result: '1-1',
child: [
{
title: '1-1-1',
result: '1-1-1',
child: [
{
title: '1-1-1-1',
result: '1-1-1-1',
child: [
{
title: '1-1-1-1-1',
result: '1-1-1-1-1',
},
],
},
{
title: '1-1-1-2',
result: '1-1-1-2',
},
{
title: '1-1-1-3',
result: '1-1-1-3',
},
],
},
],
},
],
},
{
title: '2',
result: '2',
child: [
{
title: '2-2',
result: '2-2',
},
],
},
{
title: '3',
result: '3',
},
];
with my function, it return :
[
{ title: '2', result: '2' },
{ title: '1', result: '1' },
{ title: '1-1', result: '1-1' },
{ title: '1-1-1', result: '1-1-1' },
{ title: '1-1-1-1', result: '1-1-1-1' },
{ title: '1-1-1-1-1', result: '1-1-1-1-1' },
{ title: '1-1-1-2', result: '1-1-1-2' },
{ title: '1-1-1-3', result: '1-1-1-3' },
{ title: '2-2', result: '2-2' },
{ title: '3', result: '3' },
];
How I could got a result like this:
[
{ title: '1', result: '1' },
{ title: '1-1', result: '1-1' },
{ title: '1-1-1', result: '1-1-1' },
{ title: '1-1-1-1', result: '1-1-1-1' },
{ title: '1-1-1-1-1', result: '1-1-1-1-1' },
{ title: '1-1-1-2', result: '1-1-1-2' },
{ title: '1-1-1-3', result: '1-1-1-3' },
{ title: '2', result: '2' },
{ title: '2-2', result: '2-2' },
{ title: '3', result: '3' },
];
And if you could help me to produce leaner code, feel free to help me. I'm still new in javascript
Instead of deleting/shifting/unshifting, you can extract the properties from the array item immediately with destructuring. Push the title and result to the result array as an object, then do a recursive call if child exists. This way, the result array will be the output of an ordinary depth-first strategy:
function doFlat(inputArr, resultsArr = []) {
for (const { child, title, result } of inputArr) {
resultsArr.push({ title, result });
if (child) {
doFlat(child, resultsArr);
}
}
return resultsArr;
}
By putting the results array as a default parameter which gets passed along to every recursive call, you only ever create one array, which is more efficient than creating a new array for every function call and then iterating over it in its caller.
function doFlat(inputArr, resultsArr = []) {
for (const { child, title, result } of inputArr) {
resultsArr.push({ title, result });
if (child) {
doFlat(child, resultsArr);
}
}
return resultsArr;
}
let rawData = [
{
title: '1',
result: '1',
child: [
{
title: '1-1',
result: '1-1',
child: [
{
title: '1-1-1',
result: '1-1-1',
child: [
{
title: '1-1-1-1',
result: '1-1-1-1',
child: [
{
title: '1-1-1-1-1',
result: '1-1-1-1-1',
},
],
},
{
title: '1-1-1-2',
result: '1-1-1-2',
},
{
title: '1-1-1-3',
result: '1-1-1-3',
},
],
},
],
},
],
},
{
title: '2',
result: '2',
child: [
{
title: '2-2',
result: '2-2',
},
],
},
{
title: '3-3',
result: '3-3',
},
];
console.log(doFlat(rawData));
It could get clean looking with spread operator and recursion
function flatten(dataArray) {
const result = [];
dataArray.map(d => {
const { child, ...rest } = d;
result.push(rest);
if(child && child.length) result.push(...flatten(child));
});
return result;
}
console.log(flatten(rawData));
Hope it helps
I would like to convert this json / object to this specific structure below to allow me to use a treeList component.
I've tried to build a recursive function but I didn't find the solution yet.
Thanks for your help
const data = {
parent1: {
child1: { bar: "1" },
child2: "2"
},
parent2: {
child1: "1"
}
}
to
const treeData = [
{
title: "parent1",
key: "parent1",
children: [
{
title: "child1",
key: "child1",
children: [{ title: "bar", key: "bar", value: "1" }]
},
{
title: "child2",
key: "child2",
value: "2"
}
],
},
{
title: "parent2",
key: "parent2",
children: [
{
title: "child1",
key: "child1",
value: "1"
}
]
}
]
You could take an iterative and recursive approach.
function getNodes(object) {
return Object
.entries(object)
.map(([key, value]) => value && typeof value === 'object'
? { title: key, key, children: getNodes(value) }
: { title: key, key, value }
);
}
const data = { parent1: { child1: { bar: "1" }, child2: "2" }, parent2: { child1: "1" } },
result = getNodes(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
just share sample, a little different from yours. But it give you a hint with recursive function.
https://jsfiddle.net/segansoft/7bdxmys4/1/
function getNestedChildren(arr, parent) {
var out = []
for (var i in arr) {
if (arr[i].parent == parent) {
var children = getNestedChildren(arr, arr[i].id)
if (children.length) {
arr[i].children = children
}
out.push(arr[i])
}
}
return out
}
var flat = [{
id: 1,
title: 'hello',
parent: 0
},
{
id: 2,
title: 'hello',
parent: 0
},
{
id: 3,
title: 'hello',
parent: 1
},
{
id: 4,
title: 'hello',
parent: 3
},
{
id: 5,
title: 'hello',
parent: 4
},
{
id: 6,
title: 'hello',
parent: 4
},
{
id: 7,
title: 'hello',
parent: 3
},
{
id: 8,
title: 'hello',
parent: 2
}
]
var nested = getNestedChildren(flat, 0)
document.write('<pre>' + JSON.stringify(nested, 0, 4) + '</pre>');
Here is where my algorithm skills ends. I can traverse through the object and find a certain object but I'm not able to delete the object in the same time.
Here is the object
const obj = {
children: [{
children: [
{
children: [
{
key: 'a1',
type: 'a1_type'
},
{
key: 'a2',
type: 'a2_type'
}
],
key: 'root',
type: 'root_type'
},
{
key: 'error',
type: 'error_type'
}
]
}]
}
The object with the key === 'error' object can be in any children array. I want to find it and delete the object that contains the key.
The output should be like that:
let output = findAndDeleteObjByKeyAndType('error', 'error_type')
output = {
children: [{
children: [
{
children: [
{
key: 'a1',
type: 'a1_type'
},
{
key: 'a2',
type: 'a2_type'
}
],
key: 'root',
type: 'root_type'
}
]
}]
}
Can someone help here?
Array methods like filter and every can come in handy here:
const object = {
children: [{
children: [{
children: [{
key: 'a1',
type: 'a1_type'
},
{
key: 'a2',
type: 'a2_type'
},
{
key: 'error',
type: 'error_type'
}
],
key: 'root',
type: 'root_type'
},
{
key: 'error',
type: 'error_type'
}
]
}]
}
function purgeAll (object, target) {
if (object.children) {
const keys = Object.keys(target)
object.children = object.children.filter(o =>
!keys.every(k => target[k] === o[k]) && purgeAll(o, target)
)
}
return object
}
let output = purgeAll(object, {
key: 'error',
type: 'error_type'
})
console.log(output)
.as-console-wrapper { min-height: 100%; }