Dynamically create array of objects from the object with the array values - javascript

Currently I have the below object structure,
`let selectedOptions = {
"color": {
"id": "2",
"values": [
{
"value": "red",
"label": "Red",
"id": 1
},
{
"value": "blue",
"label": "Blue",
"id": 2
}
]
},
"size": {
"id": "19",
"values": [
{
"value": "medium",
"label": "Medium",
"id": 2
}
]
},
"demo": {
"id": "19",
"values": [
{
"value": "neylon",
"label": "Neylon",
"id": 2
}
]
}
.
.
.
N
}; `
And want to create array of objects from the above object like as below,
[
{ color: "red", size: "medium", demo: "neylon" },
{ color: "blue", size: "medium", demo: "neylon" }
]
I have tried like below but it didn't worked
https://jsfiddle.net/6Lvb12e5/18/
let cArr = [];
for(key in selectedOptions) {
selectedOptions[key].values.forEach(function(val,i) {
cArr.push({ [key]: val.value })
})
}
Thanks

You could take the wanted parts, like color, size and demo and build a cartesian product out of the given data.
const
cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
options = { color: { id: "2", values: [{ value: "red", label: "Red", id: 1 }, { value: "blue", label: "Blue", id: 2 }] }, size: { id: "19", values: [{ value: "small", label: "Small", id: 1 }, { value: "medium", label: "Medium", id: 2 }] }, demo: { id: "19", values: [{ value: "neylon", label: "Neylon", id: 2 }] } },
parts = Object
.entries(options)
.map(([k, { values }]) => [k, values.map(({ value }) => value)]),
keys = parts.map(([key]) => key),
result = parts
.map(([, values]) => values)
.reduce(cartesian)
.map(a => Object.assign(...a.map((v, i) => ({ [keys[i]]: v }))));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I am not sure that is this the best way to do this, and even the data is missing but as a comment, it is quite big to post but can try:
let selectedOptions = {
"color": {
"id": "2",
"values": [
{
"value": "red",
"label": "Red",
"id": 1
},
{
"value": "blue",
"label": "Blue",
"id": 2
}
]
},
"size": {
"id": "19",
"values": [
{
"value": "medium",
"label": "Medium",
"id": 2
}
]
},
"demo": {
"id": "19",
"values": [
{
"value": "neylon",
"label": "Neylon",
"id": 2
}
]
}
};
let cArr = [];
var obj = {};
var glob;
for(key in selectedOptions) {
selectedOptions[key].values.forEach(function(val,i) {
obj[key] = val.value;
}
)
glob = obj;
}
cArr.push(glob);
console.log(cArr)

Related

I need to sort an array in javascript

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.

Creating an object which contains unique item from a nested array

I have an array of objects called employees. I need a solution that will return me a list of groups and respective employees present in the group along with the group properties.
The example is below, I have used an object but the result can also be an array that has a property called groupName within an object. [{groupName:"developer", employees:[],...}..] As long as the response returns a list of groups with their corresponding employees.
Below is the solution I did but I need a solution with a better time complexity that is O(n).
const employees = [
{ "name": "John Doe",
"id": "1",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "engineerId", "name": "engineer", "color": "#fff" }
],
"groupId":["developerId", "engineerId"]
},
{ "name": "Jane Doe",
"id": "2",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "testerId", "name": "tester", "color": "#fff" }
],
"groupId":["developerId", "testerId"]
}
]
//Solution O(m*n)
let groups = {};
employees.forEach((item) => {
item.groups.forEach((group) => {
if (!groups[group.name]) {
groups[group.name] = {
employees: [item.id],
...group,
};
} else {
groups[group.name].employees = [...groups[group.name].employees, item.id];
}
});
});
//result
{
"developer":{
"id":"developerId",
"employee":[
"1",
"2"
],
"color":"#fff"
},
"engineer":{
"id":"employeeId",
"employee":[
"1",
],
"color":"#fff"
},
"tester":{
"id":"testerId",
"employee":[
"2",
],
"color":"#fff"
}
}
Using Array#reduce and Array#forEach:
const employees = [
{
"name": "John Doe",
"id": "1",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "engineerId", "name": "engineer", "color": "#fff" }
],
"groupId": ["developerId", "engineerId"]
},
{
"name": "Jane Doe",
"id": "2",
"groups": [
{ "id": "developerId", "name": "developer", "color": "#fff" },
{ "id": "testerId", "name": "tester", "color": "#fff" }
],
"groupId": ["developerId", "testerId"]
}
];
const groups = employees.reduce((acc, { id: employeeId, groups = [] }) => {
groups.forEach(({ id, name, color }) => {
acc[name] = {
id, color, employee: [...(acc[name]?.employee ?? []), employeeId]
};
});
return acc;
}, {});
console.log(groups);
If you like to add some speed, you could use the old fashioned for statement for iterating, especially of having only a single result object.
This approach does not create an object again and again and uses the already existing objects.
const
employees = [{ name: "John Doe", id: "1", groups: [{ id: "developerId", name: "developer", color: "#fff" }, { id: "engineerId", name: "engineer", color: "#fff" }], groupId: ["developerId", "engineerId"] }, { name: "Jane Doe", id: "2", groups: [{ id: "developerId", name: "developer", color: "#fff" }, { id: "testerId", name: "tester", color: "#fff" }], groupId: ["developerId", "testerId"] }],
result = {};
for (const { id: employeeId, groups } of employees) {
for (const { id, name, color } of groups) {
result[name] ??= { id, color, employee: [] };
result[name].employee.push(employeeId);
}
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

structuring obj array based on their attributes [duplicate]

This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 1 year ago.
can you help me with this problem with js\react?
I'm trying to manage 2 arrays due to obtain a new object based on their shared attribute (Array A: "id" and Array B: "parent")
I think isn't hard but I'm struggling to do it atm :(
Array A
[{
"id": "606f1a2bebb5fb53804dd3d5",
"name": "cc",
}, {
"id": "606f1a30cfe84430c41dce88",
"name": "bb",
}, {
"id": "606f1a4ed2ff554e4ea11b82",
"name": "ff",
}]
Array B
[{
"id": "3344",
"color": "pink",
"parent": "606f1a2bebb5fb53804dd3d5",
}, {
"id": "3453",
"color": "blue",
"parent": "606f1a30cfe84430c41dce88",
}, {
"id": "3331",
"color": "yellow",
"parent": "606f1a4ed2ff554e4ea11b82",
}, {
"id": "4442",
"color": "black",
"parent": "606f1a30cfe84430c41dce88",
}]
I want merge these two arrays and create a new one where the array B objects are split by "id" of array A.
Something like this:
[{
"606f1a2bebb5fb53804dd3d5": [{
"id": "3344",
"color": "pink",
"parent": "606f1a2bebb5fb53804dd3d5",
}]
}, {
"606f1a30cfe84430c41dce88": [{
"id": "3453",
"color": "blue",
"parent": "606f1a30cfe84430c41dce88",
}, {
"id": "4442",
"color": "black",
"parent": "606f1a30cfe84430c41dce88",
}]
}, {
"606f1a4ed2ff554e4ea11b82": [{
"id": "3331",
"color": "yellow",
"parent": "606f1a4ed2ff554e4ea11b82",
}]
}]
Thanks very much guys
You just need array b for grouping and another object for keeping track of the max key inside of a group.
const
data = [{ id: "3344", color: "pink", parent: "606f1a2bebb5fb53804dd3d5" }, { id: "3453", color: "blue", parent: "606f1a30cfe84430c41dce88" }, { id: "3331", color: "yellow", parent: "606f1a4ed2ff554e4ea11b82" }, { id: "4442", color: "black", parent: "606f1a30cfe84430c41dce88" }],
max = {},
result = data.reduce((r, o) => {
max[o.parent] = (max[o.parent] || 0) + 1;
(r[o.parent] ??= {})[max[o.parent]] = o;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think you can loop through the items and then find the parent
let arrayC = [];
arrayB.forEach(item => {
let parent = array1.find(e => e.id === item.parent);
// do something here to combine it into one object
// then arrayC.push(newItem);
});
https://codesandbox.io/s/boring-snowflake-brksj?file=/src/index.js
const result = arrayA.reduce((acc, arrayAItem) => {
return {
...acc,
[arrayAItem.id]: arrayB.filter(
(arrayBItem) => arrayBItem.parent === arrayAItem.id
)
};
}, {});
}]
You can do this with map and filter functions of array.
const newArray = array1.map(array1Item => {
return { [array1Item.id]: array2.filter(array2Item => array2Item.parent === array1Item.id)}
})
Based on the two arrays that you have, I assume that they are only linked by their "parent" ids. If this is the case, you can reduce the B array using the A array as an accumulator.
const a = [
{ "id": "606f1a2bebb5fb53804dd3d5" , "name": "cc" },
{ "id": "606f1a30cfe84430c41dce88" , "name": "bb" },
{ "id": "606f1a4ed2ff554e4ea11b82" , "name": "ff" },
];
const b = [
{ "id": "3344" , "color": "pink" , "parent": "606f1a2bebb5fb53804dd3d5" },
{ "id": "3453" , "color": "blue" , "parent": "606f1a30cfe84430c41dce88" },
{ "id": "3331" , "color": "yellow" , "parent": "606f1a4ed2ff554e4ea11b82" },
{ "id": "4442" , "color": "black" , "parent": "606f1a30cfe84430c41dce88" },
];
const c = Object
.entries(b.reduce((acc, { id, color, parent }) =>
({ ...acc, [parent]: {
...acc[parent],
colors: [...acc[parent].colors, { id, color } ]
}}),
Object.fromEntries(a.map(({ id, name }) =>
[ id, { name, colors: [] } ]))))
.map(([ id, value ]) => value);
console.log(c);
.as-console-wrapper { top: 0; max-height: 100% !important; }

Filtering nested JSON array in javascript and returning inner array which matches a criteria

I have a json object like this:
{
"products": [
{
"ID": "001",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Green"
},
{
"value": "Size",
"identifier": "L"
}
],
"SKUs": [
{
"ID": "001_1",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Green"
},
{
"value": "Size",
"identifier": "L"
}
]
},
{
"ID": "001_2",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Yellow"
},
{
"value": "Size",
"identifier": "M"
}
]
}
]
},
{
"ID": "002",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Size",
"identifier": "L"
}
],
"SKUs": [
{
"ID": "002_1",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Black"
},
{
"value": "Size",
"identifier": "L"
}
]
},
{
"ID": "002_2",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Grey"
}
]
}
]
},
{
"ID": "003",
"Attributes": [
{
"value": "BESTSELLERS",
"identifier": "BEST_SELLER"
},
{
"value": "Color",
"identifier": "Blue"
}
],
"SKUs": []
}
]
}')
As you can see, products is an array which contains another array SKUs which contains another array Attributes.
I want to get all those SKUs which have BOTH the attributes - Size and Color for them.
So, it should return
SKUs 001_1, 001_2 and 002_1
So, i wrote the following code:
var obj = JSON.parse('<MyAboveJSONObjectHere>');
obj.products.filter( p => p.SKUs.filter(sku => sku.Attributes.filter(att =>
att.identifier === 'Color' && att.identifier === 'Size')))
But this is returning all 3 product objects inside the JSON.
Can you please tell what is wrong with my code expression ?
With reduce":
data.products.reduce((p, c) => (
(c.SKUs = c.SKUs.filter(
sku =>
sku.Attributes.some(att => att.value === "Color") &&
sku.Attributes.some(att => att.value === "Size")
)).length && p.push(c), p ),[]
);
data = {
products: [
{
ID: "001",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Green"
},
{
value: "Size",
identifier: "L"
}
],
SKUs: [
{
ID: "001_1",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Green"
},
{
value: "Size",
identifier: "L"
}
]
},
{
ID: "001_2",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Yellow"
},
{
value: "Size",
identifier: "M"
}
]
}
]
},
{
ID: "002",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Size",
identifier: "L"
}
],
SKUs: [
{
ID: "002_1",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Black"
},
{
value: "Size",
identifier: "L"
}
]
},
{
ID: "002_2",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Grey"
}
]
}
]
},
{
ID: "003",
Attributes: [
{
value: "BESTSELLERS",
identifier: "BEST_SELLER"
},
{
value: "Color",
identifier: "Blue"
}
],
SKUs: []
}
]
};
console.log(data.products.reduce((p, c) => (
(c.SKUs = c.SKUs.filter(
sku =>
sku.Attributes.some(att => att.value === "Color") &&
sku.Attributes.some(att => att.value === "Size")
)).length && p.push(c), p ),[]
));
If I understand correctly you're wanting to obtain a list of SKU ID values from the supplied products array where those SKU items has Attribute sub-arrays which contained values of "Color" and "Size".
This can be achieved via a reduce(), where the reduction callback filters SKU items based on the Attributes criteria. Any filtered SKU items are then mapped to their ID field, and collected (via concat()) into the resulting output array as shown below:
const obj={"products":[{"ID":"001","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Green"},{"value":"Size","identifier":"L"}],"SKUs":[{"ID":"001_1","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Green"},{"value":"Size","identifier":"L"}]},{"ID":"001_2","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Yellow"},{"value":"Size","identifier":"M"}]}]},{"ID":"002","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Size","identifier":"L"}],"SKUs":[{"ID":"002_1","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Black"},{"value":"Size","identifier":"L"}]},{"ID":"002_2","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Grey"}]}]},{"ID":"003","Attributes":[{"value":"BESTSELLERS","identifier":"BEST_SELLER"},{"value":"Color","identifier":"Blue"}],"SKUs":[]}]};
/* Filter each product by the required SKU/attribute criteria */
const result = obj.products.reduce((output, product) => {
/* Determine if this products SKUs have contain requied attribute values */
return output.concat(product.SKUs.filter((sku) => {
const attributes = sku.Attributes;
/* Search the attributes of this sku, looking for any with values that
are color or size */
const hasColor = attributes.some((attribute) => attribute.value === 'Color');
const hasSize = attributes.some((attribute) => attribute.value === 'Size');
/* If both attribute values found then this sku matches required criteria */
return hasColor && hasSize;
})
/* Map any filtered sku to it's ID and concat the result to output */
.map(sku => sku.ID));
}, []);
console.log(result);
obj.products.map( p => {
return p.SKUs.map(sku => {
return sku.Attributes.filter(att => att.identifier === 'Color' && att.identifier === 'Size')}}
Try this, basically you need to first map through the arrays and only on the last one filter
I believe that you have to check value instead of identifier. Based on your object the value you are checking for is in the value key of the attribute object. You should also be checking for the array length of the return value of the inner filters. An empty array if passed in a condition will still be considered true that's why your filter always returns all the contents of your object. so the filter should look something like this.
obj.products.filter( p => p.SKUs.filter( att => att.Attributes.filter(inner => inner.value == 'Color' || inner.value == 'Size').length > 0 ? true : false).length > 0 ? true : false)

Need to merge objects with the same keys but different values

I want to find the shortest and most beautiful way to convert an array of objects with the same values of the category key:
[{
"label": "Apple",
"category": "Fruits"
}, {
"label": "Orange",
"category": "Fruits"
}, {
"label": "Potato",
"category": "Vegetables"
}, {
"label": "Tomato",
"category": "Vegetables"
}, {
"label": "Cherry",
"category": "Berries"
}]
to the one with grouped labels from the same category:
[{
"label": ["Apple", "Orange"],
"category": "Fruits"
}, {
"label": ["Potato", "Tomato"],
"category": "Vegetables"
}, {
"label": ["Cherry"],
"category": "Berries"
}]
You could use an object as hash table and group the categories.
var data = [{ "label": "Apple", "category": "Fruits" }, { "label": "Orange", "category": "Fruits" }, { "label": "Potato", "category": "Vegetables" }, { "label": "Tomato", "category": "Vegetables" }, { "label": "Cherry", "category": "Berries" }],
grouped = [];
data.forEach(function (a) {
if (!this[a.category]) {
this[a.category] = { label: [], category: a.category };
grouped.push(this[a.category]);
}
this[a.category].label.push(a.label);
}, Object.create(null));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's how I would do this using lodash:
_(coll)
.groupBy('category')
.map((v, k) => ({
category: k,
label: _.map(v, 'label')
}))
.value()
Basically, groupBy() creates an object with unique categories as keys. Then, map() turns this object back into an array, where each item has the structure you need.
Here is my attempt to solve your problem
var result = [];
var input = [{
"label": "Apple",
"category": "Fruits"
}, {
"label": "Orange",
"category": "Fruits"
}, {
"label": "Potato",
"category": "Vegetables"
}, {
"label": "Tomato",
"category": "Vegetables"
}, {
"label": "Cherry",
"category": "Berries"
}];
var cat = [];
for(i = 0; i < input.length; i++) {
if(!cat[input[i].category]) {
cat[input[i].category] = {category: input[i].category, label:[input[i].label]};
result.push(cat[input[i].category]);
} else {
cat[input[i].category].label.push(input[i].label);
}
}
console.log(result);

Categories

Resources