Javascript nested array to object conversion - javascript

I have an array of objects in the following format. It basically a nested array of objects. I tried to do it using a recursive function, but I failed to organize the nested object.
[
{
"id": "31a3sd2f1a3ds21f",
"name": "Energy device",
"child": [
{
"id": "65sa4d65a4sdf654adsf",
"name": "Device 2",
"child": [
{
"id": "65a4d65ad4s54adsf",
"name": "Device 3",
"child": []
}
]
}
]
},
{
"id": "6as54d54as5f",
"name": "Energy device 2",
"child": [
{
"id": "9a8s7df98a78sdf",
"name": "Device 4",
"child": [
{
"id": "65a4d65ad4s54adsf",
"name": "Device 5",
"child": []
}
]
},
{
"id": "65asd54as5f4",
"name": "Device 5-1",
"child": []
}
]
}
]
I want to convert it to the following format.
{
"31a3sd2f1a3ds21f": {
"65sa4d65a4sdf654adsf": {
"65a4d65ad4s54adsf": ""
}
},
"6as54d54as5f": {
"9a8s7df98a78sdf": {
"65a4d65ad4s54adsf": ""
},
"65asd54as5f4": ""
}
}
Is there anyone who can help me?

You can map each object within your array to new arrays of the shape [key, value]. For each object, you can extract the id and child properties using desturcutring assignment in your callback argument ({id, child}) => ...). You can then return an array for that object that represents an entry for the new object your building. The key is the id of the current object, and the value is either a new object based on the child array which you can build by doing a recursive call, or an empty string if your current object doesn't have any children. This allows you to add the nesting to the objects as you build them. Finally, you can wrap the mapped version of your arr into a call to Object.fromEntries() which allows you to convert the array of [key, value] pair entries into an object:
const arr = [ { "id": "31a3sd2f1a3ds21f", "name": "Energy device", "child": [ { "id": "65sa4d65a4sdf654adsf", "name": "Device 2", "child": [ { "id": "65a4d65ad4s54adsf", "name": "Device 3", "child": [] } ] } ] }, { "id": "6as54d54as5f", "name": "Energy device 2", "child": [ { "id": "9a8s7df98a78sdf", "name": "Device 4", "child": [ { "id": "65a4d65ad4s54adsf", "name": "Device 5", "child": [] } ] }, { "id": "65asd54as5f4", "name": "Device 5-1", "child": [] } ] } ];
const mapToId = (arr) => Object.fromEntries(arr.map(({id, child}) => [
id, child.length ? mapToId(child) : ""
]));
const res = mapToId(arr);
console.log(res);

I don't know why you wanted the final child to be an empty string instead of an empty object, but here it is:
function arrayToObject(array) {
// Create empty object if array has cildren, else create an empty string
const obj = array.length > 0 ? {} : '';
// Recursively add children to object
array.forEach((item) => {
obj[item.id] = arrayToObject(item.child);
});
return obj;
}

Related

Create a tree structure from an array with parent-child references

I am trying to alter the json in snippet to a tree structure just like in https://www.primefaces.org/primeng/#/treetable (below is the sample i expect too). I understand it involves recursion but I ain't sure how to deeply link each.
The output i expect is something like below. The json whose parent is true becomes the root. If the root has values, the json corresponding to id of the value is pushed to children array with a json object "data". Again if that json has values, the json correspond to the id of value is pushed to children array with a json object "data and so on.
The code i have written is just a initial phase. Need help on how nesting can be done through iteration.
[
{
"data": {
"parent": true,
"id": "C001",
"type": "Folder",
"values": [
{
"id": "P001",
"type": "File"
}
]
},
"children": [
{
"data": {
"parent": false,
"id": "P001",
"type": "File",
"values": [
{
"id": "P002",
"type": "Image"
}
]
},
"children": [
{
"data": {
"parent": false,
"id": "P002",
"type": "Image",
"values": [
]
}
}
]
}
]
},
{
"data": {
"parent": true,
"id": "S000",
"type": "Something",
"values": [
]
}
}
]
var junkdata=[
{
"parent": false,
"id": "P001",
"type":"File",
"values": [
{
"id": "P002",
"type": "Image"
}
]
},
{
"parent": true,
"id": "C001",
"type": "Folder",
"values": [
{
"id": "P001",
"type": "File"
}]
},
{
"parent": false,
"id": "P002",
"type": "Image",
"values":[]
},
{
"parent": true,
"id": "S000",
"type": "Something",
"values":[]
}];
var parentDatas=junkdata.filter((x)=>x.parent==true);
if(parentDatas.length>0){
var finalResponse=parentDatas.map((parentData)=>{
var resultJson={};
resultJson.data=parentData;
if(parentData.values.length>0){
resultJson.children=[];
for(var i of parentData.values){
var child=junkdata.find((x)=>x.id==i.id);
if(child){
var jsonObj={};
jsonObj.data=child;
resultJson.children.push(jsonObj);
}
}
}
return resultJson;
})
}
console.log(JSON.stringify(finalResponse));
Basically, we can start with this to process the root nodes:
let tree = yourData.filter(x => x.parent).map(process);
where process is the recursive function that processes a given node:
let process = node => ({
id: node.id,
type: node.type,
children: node.values.map(x => process(
yourData.find(y => y.id === x.id)))
});
For each id in node.values, it locates a node with that id and recursively calls process on it. Once all child nodes are dealt with, process collects them into an array and returns the newly formatted object.
This is the general recursion pattern for working with graph-alike structures, where you have "nodes" somehow connected to other "nodes":
function F (N: node) {
for each node M which is connected to N {
F (M) <--- recursion
}
result = do something with N
return result
}

Iterate through a json with hierarchical children and add a key value pair

I want to convert the existing data to other. Please find below the existing code and the expected code.
Existing:
{
"title": "title1",
"child": [
{
"title": "Header",
"child":
[
{
"title": "test",
"child":
[
{
"title": "testchild",
},
{
"title": "Descriptionchild",
}
]
},
{
"title": "Description",
}
]
}
]
}
Expected:
{
"title": "title1",
"customId": "title1-xx"
"child": [
{
"title": "Header",
"customId": "Header1-xx",
"child":
[
{
"title": "test",
"customId": "test1-xx",
"child":
[
{
"title": "testchild",
"customId": "testchild1-xx"
},
{
"title": "Descriptionchild",
"customId": "Descriptionchild1-xx"
}
]
},
{
"title": "Description",
"customId": "Description1-xx"
}
]
}
]
}
We can define a function that takes an array and recursively add this attribute:
// input must be array
function recursivelyAddCustomId(input) {
// if input is not empty i.e. child is not empty
if (input != null) {
// for each child object in array
for (let obj of input) {
// set custom id
if (obj.title != null) {
obj.customId = obj.title + '-xx';
}
// recurse (doesn't matter if child exists)
recursivelyAddCustomId(obj.child);
}
}
}
// put input as array
recursivelyAddCustomId([input]);
console.log(input);
Note that the input for this function must be an array so the first object must be converted to an array first.
Please let me know if there is anything I need to clarify.
Note: Comments are made in code block

Remove base key object from array of object using lodash or javascript

I have the array of objects as below which has a base object with a set of values.
I need to remove the base object of all the data and make it as the Expected result below.
Example array
[
{
"100": {
"id": "100",
"name": "Test name 1"
},
"101": {
"id": "101",
"name": "Test name 2"
},
"102": {
"id": "102",
"name": "Test name 3"
}
}
]
Expected Result
[
{
"id": "100",
"name": "Test name 1"
},
{
"id": "101",
"name": "Test name 2"
},
{
"id": "102",
"name": "Test name 3"
}
]
You can iterate with Array.map(), get the values of the object with Object.values(), and flatten the results to a single array by spreading into Array.concat():
const data = [{"100":{"id":"100","name":"Test name 1"},"101":{"id":"101","name":"Test name 2"},"102":{"id":"102","name":"Test name 3"}}];
const result = [].concat(...
data.map(o => Object.values(o))
);
console.log(result);
With lodash you can use _.flatMap() with _.values():
const data = [{"100":{"id":"100","name":"Test name 1"},"101":{"id":"101","name":"Test name 2"},"102":{"id":"102","name":"Test name 3"}}];
const result = _.flatMap(data, _.values);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Most performant way to sort a deeply nested array of objects by another deeply nested array of objects

As an example - I've included a one element array that contains an object that has a Children key, which is an array of objects and each object also has its' own Children key that contains another array.
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
{
"Id": "100",
"DisplayName": "1-2",
},
]
}
]
}
]
There is a second array of objects that I would like to compare the first array of objects to, with the intention of making sure that the first array is in the same order as the second array of objects, and if it is not - then sort until it is.
Here is the second array:
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "100",
"DisplayName": "1-2",
},
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
]
}
]
}
]
The data that this will run on can be up in the tens of thousands - so performance is paramount.
What I'm currently attempting is using a utility method to convert each element of the second array into a keyed object of objects e.g.
{
1: {
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}
]
}
}
This allows fast look up from the top level. I'm wondering if I should continue doing this all the way down or if there is an idiomatic way to accomplish this. I considered recursion as well.
The order of the already sorted array is not based on Id - it is arbitrary. So the order needs to be preserved regardless.
Assuming same depth and all Id's exist in each level of each object use a recursive function that matches using Array#findIndex() in sort callback
function sortChildren(main, other) {
other.forEach((o, i) => {
if (o.children) {
const mChilds = main[i].children, oChilds = o.children;
oChilds.sort((a, b) => {
return mChilds.findIndex(main => main.Id === a.Id) - mChilds.findIndex(main => main.Id === b.Id)
});
// call function again on this level passing appropriate children arrays in
sortChildren(mChilds, oChilds)
}
})
}
sortChildren(data, newData);
console.log(JSON.stringify(newData, null, ' '))
<script>
var data = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "3",
"DisplayName": "1-2",
},
{
"Id": "4",
"DisplayName": "3-4",
},
]
}]
}]
var newData = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}]
}]
</script>

Comparing arrays of objects and remove duplicate [duplicate]

This question already has answers here:
Remove duplicates in an object array Javascript
(10 answers)
Closed 5 years ago.
I have an array containing arrays of objects which I need to compare.
I've looked through multiple similar threads, but I couldn't find a proper one that compares multiple arrays of objects (most are comparing two arrays of objects or just comparing the objects within a single array)
This is the data (below is a JSFiddle with code sample)
const data = [
[
{
"id": "65",
"name": "Some object name",
"value": 90
},
{
"id": "89",
"name": "Second Item",
"value": 20
}
],
[
{
"id": "89",
"name": "Second Item",
"value": 20
},
{
"id": "65",
"name": "Some object name",
"value": 90
}
],
[
{
"id": "14",
"name": "Third one",
"value": 10
}
]
]
I want to remove all duplicate arrays of objects, regardless of the length of data (there could be a lot more records).
I managed to get the unique ones extracted into an object:
const unique = data.reduce(function(result, obj) {
return Object.assign(result, obj)
}, [])
That doesn't work for me though, because I need 1 of the duplicated arrays to remain and the returned data to be an array as well, instead of an object. E.g.:
// result I need
[
[
{
"id":"65",
"name":"Some object name",
"value":90
},
{
"id":"89",
"name":"Second Item",
"value":20
}
],
[
{
"id":"14",
"name":"Third one",
"value":10
}
]
]
So how do I compare each array of objects to the others in the parent array and preserve one of each duplicated or unique array of objects?
JSFiddle
you can achieve so by using function.As below. Not sure about best optimum way of doing so.
var testArray = [
[
{
"id": "65",
"name": "Some object name",
"value": 90
},
{
"id": "89",
"name": "Second Item",
"value": 20
}
],
[
{
"id": "89",
"name": "Second Item",
"value": 20
},
{
"id": "65",
"name": "Some object name",
"value": 90
}
],
[
{
"id": "14",
"name": "Third one",
"value": 10
}
]
]
function removeDuplicatesFromArray(arr){
var obj={};
var uniqueArr=[];
for(var i=0;i<arr.length;i++){
if(!obj.hasOwnProperty(arr[i])){
obj[arr[i]] = arr[i];
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
}
var newArr = removeDuplicatesFromArray(testArray);
console.log(newArr);
const data = [
[
{
"id": "65",
"name": "Some object name",
"value": 90
},
{
"id": "89",
"name": "Second Item",
"value": 20
}
],
[
{
"id": "89",
"name": "Second Item",
"value": 20
},
{
"id": "65",
"name": "Some object name",
"value": 90
}
],
[
{
"id": "14",
"name": "Third one",
"value": 10
}
]
];
const temp = {};
const result = [];
data.forEach(itemArr => {
const items = itemArr.filter(item => {
const isUnique = temp[`${item.id}-${item.name}-${item.value}`] === undefined;
temp[`${item.id}-${item.name}-${item.value}`] = true;
return isUnique;
});
if (items.length !== 0)
result.push(items);
});
console.log(result);

Categories

Resources