Using Array.map in nested object structure in Java Script - javascript

I have below object structure in array
[
{
"modules":set of modules here
"details": [
{
"name":"abc"
"version":"1.2.3"
},
{
"name":"def"
"version":"2.3.4"
},
{
"name":"ghi"
"version":"4.5.6"
}
]
},
{
"modules":set of modules here
"details": [
{
"name":"jkl"
"version":"7.8.9"
},
{
"name":"mno"
"version":"10.11.12"
},
{
"name":"pqr"
"version":"13.14.15"
}
]
}
]
What I want to do is :
get details array transformed into below format for each root object in master array as
"details": [
{
module:"jkl:7.8.9"
},
{
module:"mno:10.11.12"
},
{
module:"pqr:13.14.15"
}
]
So final array would be :
[
{
"modules":set of modules here
"details": [
{
"module":"abc:1.2.3"
},
{
"module":"def:2.3.4"
},
{
"module":"ghi:4.5.6"
}
]
},
{
"modules":set of modules here
"details": [
{
"module":"jkl:7.8.9"
},
{
"module":"mno:10.11.12"
},
{
"module":"pqr:13.14.15"
}
]
}
]
What I have tried and is working is :
rootArray.forEach((entry)=> {
let line = entry.details.map((detailEntry)=>{
//merge detailEntry into single line
})
entry.details = line
});
My question is : is this a right approach or is there any better solution available ?

Two maps is probably the right approach. It will return a new array rather than mutating the original array.
map over the main data array, and then assign the result of mapping over details to the details property of the object that you're returning on each iteration.
const data=[{modules:"set of modules here",details:[{name:"abc",version:"1.2.3"},{name:"def",version:"2.3.4"},{name:"ghi",version:"4.5.6"}]},{modules:"set of modules here",details:[{name:"jkl",version:"7.8.9"},{name:"mno",version:"10.11.12"},{name:"pqr",version:"13.14.15"}]}];
const out = data.map(obj => {
return {
modules: obj.modules,
details: obj.details.map(detail => {
const { name, version } = detail;
return { module: `${name}:${version}` };
})
};
});
console.log(out);
Additional documentation
Destructuring assignment
map
Template/string literals

const data = [
{
"modules": "set of modules here",
"details": [
{
"name":"abc",
"version":"1.2.3"
},
{
"name":"def",
"version":"2.3.4"
},
{
"name":"ghi",
"version":"4.5.6"
}
]
},
{
"modules": "set of modules here",
"details": [
{
"name":"jkl",
"version":"7.8.9"
},
{
"name":"mno",
"version":"10.11.12"
},
{
"name":"pqr",
"version":"13.14.15"
}
]
}
]
const result = data.map( item => ({modules: item.modules, details: item.details.map(i => {
return { module: `${i["name"]}:${i["version"]}` }
})}))
console.log(result)

your approach seems correct.
there is another way to achieve the expected structure, making the copy of the initial array however instead of modifying the existing.
const result = rootArray.map(({ details, ...rest }) => ({
details: details.map(/*transform*/),
...rest
));

Related

How can I sort a javascript array of objects that specify prerequisites between them?

I have an array of objects that determine which ones should be showed first. An example of this array would be:
[
{
"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870",
"prerequisites_ids": [
"2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"
]
},
{
"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7",
"prerequisites_ids": [
"74e41a2c-e74e-4016-bb2c-f2e84c04fe92"
]
},
{
"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92",
"prerequisites_ids": []
},
{
"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1",
"prerequisites_ids": [
"ef7d2415-808f-4efc-939e-2692f38a5ee7"
]
}
]
How could I sort it to get this?
[
{
"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92",
"prerequisites_ids": []
},
{
"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7",
"prerequisites_ids": [
"74e41a2c-e74e-4016-bb2c-f2e84c04fe92"
]
},
{
"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1",
"prerequisites_ids": [
"ef7d2415-808f-4efc-939e-2692f38a5ee7"
]
},
{
"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870",
"prerequisites_ids": [
"2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"
]
}
]
I have tried creating a custom function:
export function comparePrerequisites(a, b) {
if (!a.prerequisites_ids) {
return -1
}
if (a.prerequisites_ids.includes(b.id)) {
return 1;
}
}
data.sort(comparePrerequisites)
but does not seem to work. Thanks in advance!
We have here the requirements for a topological sort. This is not a job for the sort method. Instead you can use recursion (a DFS traversal) to drill down to a dependency that is already collected, or to a leaf (no dependencies).
Here is an implementation:
function topologicalSort(tasks) {
const visited = new Set;
const taskMap = new Map(tasks.map(task => [task.id, task]));
function dfs(tasks) {
for (let task of tasks) {
if (!visited.has(task.id)) {
dfs(task.prerequisites_ids.map(id => taskMap.get(id)));
}
visited.add(task);
}
}
dfs(tasks);
return [...visited];
}
// Demo on your example:
let tasks = [{"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870","prerequisites_ids": ["2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"]},{"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7","prerequisites_ids": ["74e41a2c-e74e-4016-bb2c-f2e84c04fe92"]},{"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92","prerequisites_ids": []},{"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1","prerequisites_ids": ["ef7d2415-808f-4efc-939e-2692f38a5ee7"]}];
console.log(topologicalSort(tasks));

Remove object from a nested object javascript

I have an object:
s={
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
]
}
}
I need to remove a nested object from the array of values of ex_obj such that the value of version meets a criteria and store the key of that object it's key in an array.
For example, if I want the object without the child object with a version "2020-04-29t14:14:09" my output would be
{
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
}
]
}
}
Along with an array ['arr1', 'arr2'] as I want the array of keys whose values have been changed.
Here is my attempt. I could remove the object but of course couldn't capture the key.
Object.values(s['ex_obj']).map(e =>e)
.map(x =>
x.filter((f) => {
return f.version != "2020-04-29t14:14:09";
}));
How can I go about getting the output?
x is a local variable containing a reference to the array. Assigning to it doesn't modify the property it came from.
Use Object.entries() so you get both the property name and value, then you can assign back to the property. This will also allow you to make the array of properties that were modified.
s = {
"ex_obj": {
"arr1": [{
"id": "item1",
"version": "2020-04-29t14:14:08"
},
{
"id": "item1",
"version": "2020-04-29t14:14:09"
}
],
"arr2": [{
"id": "item1",
"version": "2020-04-29t14:14:10"
},
{
"id": "item1",
"version": "2020-04-29t14:14:09"
}
]
}
}
let updated = [];
let remove = "2020-04-29t14:14:09";
Object.entries(s.ex_obj).forEach(([key, array]) => {
let filtered = array.filter(({
version
}) => version != remove);
if (filtered.length < array.length) {
s.ex_obj[key] = filtered;
updated.push(key);
}
});
console.log(s);
console.log(updated);
If you are allowed to destroy the original object, you could just loop over the keys and then filter the arrays:
let s={
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
]
}
}
let ex_obj=s.ex_obj;
for(let key of Object.keys(ex_obj))
ex_obj[key]=ex_obj[key].filter(item=>item.version!=="2020-04-29t14:14:09");
console.log(s);
If you have to make a copy, that's not very different either, just you have to use some kind of cloning, like the JSON-hack, or another:
let s={
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
]
}
}
let ex_obj=s.ex_obj;
let result={};
for(let key of Object.keys(ex_obj))
result[key]=JSON.parse(JSON.stringify(ex_obj[key].filter(item=>item.version!=="2020-04-29t14:14:09")));
result={ex_obj:result};
console.log(result);

How do I push object elements from GraphQL into nested array in javascript object?

I do currently map through GraphQL data like so:
const plotDataArray = data.allWordpressWpPlots.edges.map(plot => (
{
geometry: {
type: plot.node.properties.geotype,
coordinates: [
[
plot.node.coordinates[0].coord.split(",").reverse(),
plot.node.coordinates[1].coord.split(",").reverse(),
plot.node.coordinates[2].coord.split(",").reverse(),
plot.node.coordinates[3].coord.split(",").reverse(),
plot.node.coordinates[4].coord.split(",").reverse()
]
]
}
}
))
The GraphQL query I use looks like this:
query {
allWordpressWpPlots {
edges {
node {
coordinates {
coord
}
}
}
}
}
..and the output from GraphiQL looks like this:
{
"data": {
"allWordpressWpPlots": {
"edges": [
{
"node": {
"coordinates": [
{
"coord": "56.064655444812,9.6949704566207"
},
{
"coord": "56.064575958599,9.6994982706574"
},
{
"coord": "56.06046088577,9.6994719476694 "
},
{
"coord": "56.060440367157,9.6951515896261"
},
{
"coord": "56.064655444812,9.6949704566207"
}
]
}
}
]
}
}
}
The map function do return an object in the correct format, but my problem is that the "coordinates" node from GrapQL comes in different lengths. I want to loop through the node using a foreach-loop based on the length of the array, but I get a syntax error when I try to javascript within the map function.
How can I build a "coordinates" array with X amount of object elements from GraphQL?
You can nest map calls. Not quite sure why coordinates is an array inside another array, but keeping that as is:
const plotDataArray = data.allWordpressWpPlots.edges.map(plot => ({
geometry: {
type: plot.node.properties.geotype,
coordinates: [
plot.node.coordinates.map(coordinate => {
return coordinate.coord.split(",").reverse()
}),
]
},
}))

Group an array on an attribute and make that attribut a parent array

With An example, I'm basically trying to go from :
[
{
'a':a1,
'b':b2
},
{
'a':a1,
'b':b5
},
{
'a':a3,
'b':b4
}
]
To :
[
{
'group':'a1',
'content':[
{
'a':a1,
'b':b2
},
{
'a':a1,
'b':b5
}
],
},
{
'group':'a3',
'content':[
{
'a':a3,
'b':b4
}
]
}
]
So in word reformat the array and group elements on an attribute, here a
There is a simple way by using lodash GroupBy
https://lodash.com/docs#groupBy
_.groupBy([
{
'a':"a1",
'b':"b2"
},
{
'a':"a1",
'b':"b5"
},
{
'a':"a3",
'b':"b4"
}
], "a")
The first arguments the array you want to group, an the second is the iterator you want to group, the result will be grouped in a array, it will not have the content preoperty.
{
"a1":[
{
"a":"a1",
"b":"b2"
},
{
"a":"a1",
"b":"b5"
}
],
"a3":[
{
"a":"a3",
"b":"b4"
}
]
}
See if this helps get you going, if not, let me know
If you only want that grouped array then you can achieve using reducer.
`let group = data.reduce((r, a) => {
r[a.a] = [...r[a.a] || [], a];
return r;
}, {});`
var data = [
{
'a':'a1',
'b':'b2'
},
{
'a':'a1',
'b':'b5'
},
{
'a':'a3',
'b':'b4'
}
]
let group = data.reduce((r, a) => {
r[a.a] = [...r[a.a] || [], a];
return r;
}, {});
console.log("group", group);

Creating result array based on 2 arrays using JavaScript ES6 Reduce method

Hi actually i have two arrays ( services and offer) and i'm trying connect offer array with service array based on service id using reduce method and i tried different method but nothing working i'm not able to solve this check my js fiddle link (not able to connect with offer array). please help me to resolve this. thanks in advance
const services = [
{
cid:1,
catname:'Facial',
services:[
{
sid:30,
sname:'Fruit facial'
},
{
sid:33,
sname:'Herbal facial'
}
]
},
{
cid:2,
catname:'Massage',
services:[
{
sid:40,
sname:'Head Massage'
},
{
sid:45,
sname:'Back Massage'
},
{
sid:46,
sname:'Face Massage'
}
]
}
]
Offer Array - here based on service id (sid) i want to connect with services array and create new array
const offer = [
{
offid:1,
sid:'33,40'
offvalue : 10%
},
{
offid:2,
sid:'45,46',
offvalue : 100
}
]
Expecting Result:
const Result = [
{
cid:1,
catname:'Facial',
services:[
{
sid:30,
sname:'Fruit facial'
},
{
sid:33,
sname:'Herbal facial',
offid:1,
offvalue : 10%
}
]
},
{
cid:2,
catname:'Massage',
services:[
{
sid:40,
sname:'Head Massage',
offid:1,
offvalue : 10%
},
{
sid:45,
sname:'Back Massage',
offid:2,
offvalue : 100
},
{
sid:46,
sname:'Face Massage',
offid:2,
offvalue : 100
}
]
}
]
If you can use ES6 features, then this should work:
const services = [{
cid:1,
catname:'Facial',
services: [{
sid:30,
sname:'Fruit facial'
}, {
sid:33,
sname:'Herbal facial'
}],
}, {
cid:2,
catname:'Massage',
services: [{
sid:40,
sname:'Head Massage'
}, {
sid:45,
sname:'Back Massage'
}, {
sid:46,
sname:'Face Massage'
}],
}];
const offer = [{
offid:1,
sid:'33,40',
offvalue : "10%"
}, {
offid:2,
sid:'45,46',
offvalue : "100"
}];
const result = services.map(val => {
return {
...val,
services: val.services.map(serv => {
// Here is where we find any matching offers, then add their data to the service.
const off = offer.find(x => x.sid.split(",").includes(String(serv.sid)));
if (off) {
serv.offid = off.offid;
serv.offvalue = off.offvalue;
}
return serv;
}),
}
});
console.log(result);

Categories