Related
I am getting json data like this
[
{
"emission": [
{
"id": "fffda276-c7ed-4931-8211-48b3ae304b6f",
"size": "Medium",
}
],
"id": "db9dd205-5986-432f-9aaf-1079d6fdd28c",
},
{
"emission": [
{
"id": "5ae8991c-bbcd-4a97-a5ad-b1aac6d765c0",
"size": "",
},
{
"id": "f670609a-d200-4c03-a8a7-34e2b244a4c7",
"size": "Small",
}
],
"id": "95a9c2eb-7dac-45d6-9a6a-2718859d91f3",
},
{
"emission": [
{
"id": "77f5b953-772a-4e02-834f-6d7eb4236223",
"size": "Medium",
},
{
"id": "04e909bc-0087-479d-9f4d-8f4ad03f8dd0",
"size": "Large",
},
{
"id": "4a628027-3ec8-450c-943e-7dce96f0bbb4",
"size": "Small",
},
{
"id": "7c5c638b-bab6-4a10-ba3e-ebdc8939021d",
"size": "Large",
}
],
"id": "bc38b226-78cd-4928-80a0-589a9da2cd40",
},
{
"emission": [
{
"id": "e6011db7-0662-4b52-9d26-e6be07226826",
"size": "Large",
},
{
"id": "ad678447-3e18-4537-baa1-b762dc03f6cd",
"size": "Medium",
}
],
"id": "e1c59ebd-b567-462f-ac00-068ff7938055",
},
{
"emission": [
{
"id": "3525d215-e9eb-4417-8b35-902936181d29",
"size": "Medium",
},
{
"id": "4c023985-a3c0-4783-a9c3-d51a21bf63d9",
"size": "Large",
},
{
"id": "7ef8d908-8a29-4d40-bdfe-121895d01ebc",
"size": "Medium",
}
],
"id": "d9e88ddc-1b7e-4a68-b087-46d365f266a3",
}
]
I need to reorder entire data based on emission array's size like large, medium and small, so that first array must be no of count of Large, then medium and small, it needs to be sorted
Note: some data can also be without size those data can be omitted, but still needs to be present in final sorted array
Output:
[
{
"emission": [
{
"id": "77f5b953-772a-4e02-834f-6d7eb4236223",
"size": "Medium",
},
{
"id": "04e909bc-0087-479d-9f4d-8f4ad03f8dd0",
"size": "Large",
},
{
"id": "4a628027-3ec8-450c-943e-7dce96f0bbb4",
"size": "Small",
},
{
"id": "7c5c638b-bab6-4a10-ba3e-ebdc8939021d",
"size": "Large",
}
],
"id": "bc38b226-78cd-4928-80a0-589a9da2cd40",
},
{
"emission": [
{
"id": "3525d215-e9eb-4417-8b35-902936181d29",
"size": "Medium",
},
{
"id": "4c023985-a3c0-4783-a9c3-d51a21bf63d9",
"size": "Large",
},
{
"id": "7ef8d908-8a29-4d40-bdfe-121895d01ebc",
"size": "Medium",
}
],
"id": "d9e88ddc-1b7e-4a68-b087-46d365f266a3",
},
{
"emission": [
{
"id": "e6011db7-0662-4b52-9d26-e6be07226826",
"size": "Large",
},
{
"id": "ad678447-3e18-4537-baa1-b762dc03f6cd",
"size": "Medium",
}
],
"id": "e1c59ebd-b567-462f-ac00-068ff7938055",
},
{
"emission": [
{
"id": "fffda276-c7ed-4931-8211-48b3ae304b6f",
"size": "Medium",
}
],
"id": "db9dd205-5986-432f-9aaf-1079d6fdd28c",
},
{
"emission": [
{
"id": "5ae8991c-bbcd-4a97-a5ad-b1aac6d765c0",
"size": "",
},
{
"id": "f670609a-d200-4c03-a8a7-34e2b244a4c7",
"size": "Small",
}
],
"id": "95a9c2eb-7dac-45d6-9a6a-2718859d91f3",
}
]
You could count wanted type and sort descending.
const
count = ({ emission }, type) =>
emission.reduce((r, { size }) => r + (type === size), 0),
data = [{ emission: [{ id: "fffda276-c7ed-4931-8211-48b3ae304b6f", size: "Medium" }], id: "db9dd205-5986-432f-9aaf-1079d6fdd28c" }, { emission: [{ id: "5ae8991c-bbcd-4a97-a5ad-b1aac6d765c0", size: "" }, { id: "f670609a-d200-4c03-a8a7-34e2b244a4c7", size: "Small" }], id: "95a9c2eb-7dac-45d6-9a6a-2718859d91f3" }, { emission: [{ id: "77f5b953-772a-4e02-834f-6d7eb4236223", size: "Medium" }, { id: "04e909bc-0087-479d-9f4d-8f4ad03f8dd0", size: "Large" }, { id: "4a628027-3ec8-450c-943e-7dce96f0bbb4", size: "Small" }, { id: "7c5c638b-bab6-4a10-ba3e-ebdc8939021d", size: "Large" }], id: "bc38b226-78cd-4928-80a0-589a9da2cd40" }, { emission: [{ id: "e6011db7-0662-4b52-9d26-e6be07226826", size: "Large" }, { id: "ad678447-3e18-4537-baa1-b762dc03f6cd", size: "Medium" }], id: "e1c59ebd-b567-462f-ac00-068ff7938055" }, { emission: [{ id: "3525d215-e9eb-4417-8b35-902936181d29", size: "Medium" }, { id: "4c023985-a3c0-4783-a9c3-d51a21bf63d9", size: "Large" }, { id: "7ef8d908-8a29-4d40-bdfe-121895d01ebc", size: "Medium" }], id: "d9e88ddc-1b7e-4a68-b087-46d365f266a3" }];
data.sort((a, b) =>
count(b, 'Large') - count(a, 'Large') ||
count(b, 'Medium') - count(a, 'Medium') ||
count(b, 'Small') - count(a, 'Small')
);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I couldn't fully understand what you meant, but I assume a sorting by Large, Medium and Small might help you
let data = [
{
"emission": [
{
"id": "fffda276-c7ed-4931-8211-48b3ae304b6f",
"size": "Medium",
}
],
"id": "db9dd205-5986-432f-9aaf-1079d6fdd28c",
},
// ... other data objects
];
let sortedData = data.sort((a, b) => {
let aCount = countSizes(a.emission, 'Large');
let bCount = countSizes(b.emission, 'Large');
if (aCount !== bCount) {
return bCount - aCount;
}
aCount = countSizes(a.emission, 'Medium');
bCount = countSizes(b.emission, 'Medium');
if (aCount !== bCount) {
return bCount - aCount;
}
aCount = countSizes(a.emission, 'Small');
bCount = countSizes(b.emission, 'Small');
return bCount - aCount;
});
function countSizes(emission, size) {
return emission.filter(e => e.size === size).length;
}
console.log(sortedData);
Explanation:
In the code, the countSizes function is used to count the number of occurrences of a specific size in the emission array. The sort method is used to sort the data array based on the number of occurrences of Large, Medium, and Small sizes, in that order. The resulting sortedData array will have the data objects ordered based on the number of occurrences of the sizes in the emission array.
I need to get the parent id of the specific child.
Here is my sample JSON, If I give entity id 32 it should return 6 as parent Id and if I give 30 it should return 5 as parent id.
const arr = [{
"id": 0,
"name": "My Entity",
"children": [
{
"id": 1,
"name": "MARKET",
"children": [
{
"id": 2,
"name": "Sales",
"children": [
{
"id": 3,
"name": "District 1",
"children": [
{
"id": 5,
"name": "Area 1",
"children": [
{
"entityId": 30,
"id": 26,
"name": "Mumbai"
},
{
"entityId": 31,
"id": 26,
"name": "Hyderabad"
}
],
"num": 0,
},
{
"id": 6,
"name": "Area 2",
"children": [
{
"entityId": 32,
"id": 32,
"name": "Karnataka"
},
{
"entityId": 33,
"id": 33,
"name": "Andhra Pradesh"
}
],
"num": 0,
},
]
},
]
},
]
},
]
}]
Here is the code I have tried
const findParent = (arr, entityId) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].entityId === entityId) {
return [];
} else if (arr[i].children && arr[i].children.length) {
const t = findParents(arr[i].children, entityId);
if (t !== false) {
t.push(arr[i].id);
return t;
}
}
}
return false;
};
findParents(arr, 30);
But it is returning like below
[
5,
3,
2,
1,
0
]
But I want the output to be
[
5
]
Kindly help me on this, thanks
Replace this:
t.push(arr[i].id);
with:
if (t.length == 0) t.push(arr[i].id);
I would suggest easier solution
const findParent = (arr, entityId) => {
const children = arr.flatMap(parent =>
(item.children || []).map(child => ({ parent, child, entityId: child.entityId }))
)
const res = children.find(item => item.entityId === entityId)
return res.entityId || findChildren(res.map(v => v.child), entityId)
}
I'm trying to group a big nested object with multiple properties such as this one :
[
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 70,
"name": "Name70"
}
},
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 61,
"name": "Name61"
}
},
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 4,
"name": "Name4",
"sub": {
"id": 5,
"name": "Name5",
"sub": {
"id": 29,
"name": "Name29"
}
}
}
},
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 4,
"name": "Name4",
"sub": {
"id": 5,
"name": "Name5",
"sub": {
"id": 8,
"name": "Name8",
"sub": {
"id": 163,
"name": "Name163"
}
}
}
}
},
{
"id": 10,
"name": "Name10",
"sub": {
"id": 4,
"name": "Name4"
}
}
]
As you can see, the "sub" are not arrays as of now, but they would be in the expected output even if there's only one object in it.
I'd like to group the array by object's id recursively to get this kind of output :
[
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": [
{
"id": 70,
"name": "Name70"
},
{
"id": 61,
"name": "Name61"
},
{
"id": 4,
"name": "Name4",
"sub": [
{
"id": 5,
"name": "Name5",
"sub": [
{
"id": 29,
"name": "Name29"
},
{
"id": 8,
"name": "Name8",
"sub": [
{
"id": 163,
"name": "Name163"
}
]
}
]
}
]
}
]
},
{
"id": 10,
"name": "Name10",
"sub": [
{
"id": 4,
"name": "Name4"
}
]
}
]
So far, I tried some shenanigans with lodash and d3.nest() but I just can't seem to group it.
Have you guys ever face something similar? And if so, how did you manage to code this?
Thanks a lot
You could take a recursive approach with a function which merges an object into an array by looking for same id.
const
merge = (target, { sub, ...o }) => {
let temp = target.find(({ id }) => id === o.id);
if (sub) sub = merge(temp?.sub || [], sub)
if (!temp) target.push(temp = { ...o, sub });
return target;
};
var data = [{ id: 14, name: "Name14", theme: true, sub: { id: 70, name: "Name70" } }, { id: 14, name: "Name14", theme: true, sub: { id: 61, name: "Name61" } }, { id: 14, name: "Name14", theme: true, sub: { id: 4, name: "Name4", sub: { id: 5, name: "Name5", sub: { id: 29, name: "Name29" } } } }, { id: 14, name: "Name14", theme: true, sub: { id: 4, name: "Name4", sub: { id: 5, name: "Name5", sub: { id: 8, name: "Name8", sub: { id: 163, name: "Name163" } } } } }, { id: 10, name: "Name10", sub: { id: 4, name: "Name4" } }],
result = data.reduce(merge, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could create a Map for each sub property -- keyed by id -- and merge the objects into those maps. Then finally convert those sub-maps back to sub-arrays:
function mergeArray(arr) {
function mergeObject(a, b) {
while (b = b.sub) {
if (!a.sub) a.sub = new Map;
let child = a.sub.get(b.id);
if (child) a = child;
else a.sub.set(b.id, a = { id: b.id, name: b.name });
}
}
function convertMap(map) {
return Array.from(map.values(), obj => {
if (obj.sub) obj.sub = convertMap(obj.sub);
return obj;
});
}
let map = new Map(arr.map(({id, name}) => [id, {id, name}]));
for (let item of arr) mergeObject(map.get(item.id), item);
return convertMap(map);
}
// Demo with input from question
let input = [{"id": 14,"name": "Name14","theme": true,"sub": {"id": 70,"name": "Name70"}},{"id": 14,"name": "Name14","theme": true,"sub": {"id": 61,"name": "Name61"}},{"id": 14,"name": "Name14","theme": true,"sub": {"id": 4,"name": "Name4","sub": {"id": 5,"name": "Name5","sub": {"id": 29,"name": "Name29"}}}},{"id": 14,"name": "Name14","theme": true,"sub": {"id": 4,"name": "Name4","sub": {"id": 5,"name": "Name5","sub": {"id": 8,"name": "Name8","sub": {"id": 163,"name": "Name163"}}}}},{"id": 10,"name": "Name10","sub": {"id": 4,"name": "Name4"}}];
console.log(mergeArray(input));
I would do it with recursive functions, because I think those are more versatile:
const data = [{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 70,
"name": "Name70"
}
},
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 61,
"name": "Name61"
}
},
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 4,
"name": "Name4",
"sub": {
"id": 5,
"name": "Name5",
"sub": {
"id": 29,
"name": "Name29"
}
}
}
},
{
"id": 14,
"name": "Name14",
"theme": true,
"sub": {
"id": 4,
"name": "Name4",
"sub": {
"id": 5,
"name": "Name5",
"sub": {
"id": 8,
"name": "Name8",
"sub": {
"id": 163,
"name": "Name163"
}
}
}
}
},
{
"id": 10,
"name": "Name10",
"sub": {
"id": 4,
"name": "Name4"
}
}
]
// setting up arrays
const recursiveModify = (node) => {
if (typeof node.sub === "undefined") {
return node
} else {
node.sub = [recursiveModify(node.sub)]
return node
}
}
const recursiveReduce = (nodes) => {
return nodes.reduce((a, c) => {
const item = a.find(e => e.id === c.id)
if (!item) {
a.push(c)
} else {
item.sub = recursiveReduce([...item.sub, ...c.sub])
}
return a
}, [])
}
const dataWithArray = data.map(node => {
return recursiveModify(node)
})
const result = recursiveReduce(dataWithArray)
console.log(result)
Unfortunately I could only do it with two passes - one for creating the sub as arrays, then one for actually grouping the data. I'm pretty sure it can be done in one pass - I just have no more time to work it out.
I'm learning TypeScript and JS and struggling to solve multiple problems. One of them is this, that I have at hand. Say, I have an array of Application objects. Each Application object has this kind of a nested structure:
Application
|
----[Document Type]
---------|
--------------[Document]
------------------|
------------------------Metadata
(Each Application has an array of Document Type.
Each Document Type has an array of Document.
Each Document has a Metadata inside it)
All the three objects types -- Application, Document Type, Document...have a property called name inside them.
I want to sort the entire array of Application objects (and recursively the nested objects as well), based on ascending order of the name property of each object. I had been trying multiple examples, but those are all sorting only the root level objects (Application) and not the nested objects.
Here is one such example I tried:
var simplePropertyRetriever = function(obj:any) {
return obj.name;
};
function sortArrayByName(propertyRetriever, arr:Application[]) {
arr.sort(function (a, b) {
var valueA = propertyRetriever(a);
var valueB = propertyRetriever(b);
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
});
};
Can anybody please advise how to do this?
My sample JSON is this (I have arranged the objects in descending order here, to better explain my use case):
[
{
"name": "Application 2",
"children": [
{
"name": "Operations Manual",
"children": [
{
"name": "2nd-opsManual-app1",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-opsManual-app1",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
},
{
"name": "Interface Contracts",
"children": [
{
"name": "2nd-IntContracts-app1",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-IntContracts-app1",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
}
]
},
{
"name": "Application 2",
"children": [
{
"name": "User Manual",
"children": [
{
"name": "2nd-userManual-app2",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-userManual-app2",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
},
{
"name": "System Design",
"children": [
{
"name": "2nd-SystemDesign-app2",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-SystemDesign-app2",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
}
]
}
]
You could iterate the array and take the children for a new sorting.
function sort(array) {
array.forEach(({ children = [] }) => sort(children));
array.sort((a, b) => a.name.localeCompare(b.name));
}
var data = [{ name: "Application 2", children: [{ name: "Operations Manual", children: [{ name: "2nd-opsManual-app1", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-opsManual-app1", metadata: { size: 56, fileExtension: "pdf" } }] }, { name: "Interface Contracts", children: [{ name: "2nd-IntContracts-app1", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-IntContracts-app1", metadata: { size: 56, fileExtension: "pdf" } }] }] }, { name: "Application 2", children: [{ name: "User Manual", children: [{ name: "2nd-userManual-app2", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-userManual-app2", metadata: { size: 56, fileExtension: "pdf" } }] }, { name: "System Design", children: [{ name: "2nd-SystemDesign-app2", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-SystemDesign-app2", metadata: { size: 56, fileExtension: "pdf" } }] }] }];
sort(data);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Your code is working, but you're only doing a shallow sort. If you need to also sort each application object's children, you can recursively call sortArrayByName on each application object's children (if they exist).
var simplePropertyRetriever = function(obj) {
return obj.name;
};
function sortArrayByName(propertyRetriever, arr) {
arr.forEach(function(obj) {
if (Array.isArray(obj.children)) {
sortArrayByName(propertyRetriever, obj.children);
}
});
arr.sort(function (a, b) {
var valueA = propertyRetriever(a);
var valueB = propertyRetriever(b);
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
});
};
const data = [
{
"name": "Application 2",
"children": [
{
"name": "Operations Manual",
"children": [
{
"name": "2nd-opsManual-app1",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-opsManual-app1",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
},
{
"name": "Interface Contracts",
"children": [
{
"name": "2nd-IntContracts-app1",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-IntContracts-app1",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
}
]
},
{
"name": "Application 2",
"children": [
{
"name": "User Manual",
"children": [
{
"name": "2nd-userManual-app2",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-userManual-app2",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
},
{
"name": "System Design",
"children": [
{
"name": "2nd-SystemDesign-app2",
"metadata": {
"size": 56,
"fileExtension": "docx"
}
},
{
"name": "1st-SystemDesign-app2",
"metadata": {
"size": 56,
"fileExtension": "pdf"
}
}
]
}
]
}
];
sortArrayByName(simplePropertyRetriever, data);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For example: I have an array of objects like this:
let arrayOfObjects: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
Now I want to replace or overwrite the array above with the same array, but including different values (same keys, different values):
let arrayOfObjects: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
How can this be done in TypeScript?
Try this JS
let oneArray = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let twoArray = [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
let newArray = Object.assign([], oneArray, twoArray);
console.log(newArray);
In TS
interface Data {
oneArray: array;
twoArray: array;
}
function merge(data: Data) {
return Object.assign([], data.oneArray, data.twoArray);
}
let user = {
oneArray: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
],
twoArray: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
]
};
console.log(merge(user));
Sure :)
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
const newValues = ['Not Available', 'Not Ready', 'Not Started'];
newValues.forEach((value, i) => {
arrayOfObjects.find(o => o.id === i).name = value;
});
console.log(arrayOfObjects);
I wouldn't recommend this though: functional programming is awesome.
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let names = ['Not Available', 'Not Ready', 'Not Started']
let result = arrayOfObjects.map((user, index) => ({ ...user, name: names[index] }))
console.log(result)