Restructuring a JSON file in javascript - javascript

I have a JSON called 'from' that I want to convert to 'to' as follows. What is the fastest and most efficient way to achieve it? Is it possible to do in one step or should I reduce the duplicates first?:
const from =[{
NUM: '1234001',
SUBNUM: '001'},
{
NUM: '1234001',
SUBNUM: '001'},
{
NUM: '1234002',
SUBNUM: '002'},
{
NUM: '1234005',
SUBNUM: '005'},
{
NUM: '4567001',
SUBNUM: '001'},
{
NUM: '9999001',
SUBNUM: '001'}
];
const to = [{
label: 'SUBNUM',
submenu: [{
label: '1234',
role: '1234',
submenu: [{
label: '001',
role: '001'
},
{
label: '002',
role: '002'
},
{
label: '005',
role: '005'
}]
},{
label: '4567',
role: '4567',
submenu: [{
label: '001',
role: '001'
}]
},{
label: '9999',
role: '9999',
submenu: [{
label: '001',
role: '001'
}]
}
]}];

You can try following code:
let items = [];
from.forEach(obj => {
let numTruncated = obj.NUM.replace(obj.SUBNUM, "");
let currentNum = items.find(n => n.label === numTruncated);
if(!currentNum ) {
currentNum = {
label: numTruncated,
role: numTruncated,
submenu: []
};
items.push(currentNum );
}
if(!currentNum .submenu.find(item => item.label === obj.SUBNUM)){
currentNum .submenu.push({ label: obj.SUBNUM, role: obj.SUBNUM });
}
});
let output = { label: "SUBNUM", submenu: items };
find returns undefined if there's no element matching specified arrow function, using replace from string prototype to get rid of SUBNUM

Related

Create an array of objects with values from another object

I have an object looking like this
const item = {
id: 123,
type: 'book',
sections: [{
type: 'section',
id: '456',
index: 1,
lessons: [{
type: 'lesson',
id: 789,
index: 1
},
{
type: 'lesson',
id: 999,
index: 2
}
]
}, {
type: 'section',
index: 2,
id: 321,
lessons: [{
type: 'lesson',
id: 444,
index: 1
},
{
type: 'lesson',
id: 555,
index: 2
}
]
}]
}
It should be assumed that there are more objects in sections and lessons array. I want to create a new object like this
result = [{
section: 456,
lessons: [789, 999]
}, {
section: 321,
lessons: [444, 555]
}]
I tried this loop but this just pushes indexes and not lesson's ids
let obj = {};
let sectionWithLessons = [];
let lessons = []
for (const i in item.sections) {
obj = {
sectionId: item.sections[i].id,
lessonIds: item.sections[i].lessons.map((lesson) => {
return lessons.push(lesson.id)
}),
};
sectionWithLessons.push(obj);
}
console.log(sectionWithLessons);
How can i do this correctly and preferably with good performance in consideration?
I believe the best/shortest thing is to use the map function, like:
const result2 = item.sections.map(({id, lessons}) => ({
id,
lessons: lessons.map(({id: lessionId}) => lessionId)
}))
I would suggest using Array.map() to convert the item sections to the desired result.
We'd convert each section into an object with a section value and lessons array.
To create the lessons array, we again use Array.map() to map each lesson to a lesson id.
const item = { id: 123, type: 'book', sections: [{ type: 'section', id: '456', index: 1, lessons: [{ type: 'lesson', id: 789, index: 1 }, { type: 'lesson', id: 999, index: 2 } ] }, { type: 'section', index: 2, id: 321, lessons: [{ type: 'lesson', id: 444, index: 1 }, { type: 'lesson', id: 555, index: 2 } ] }] }
const result = item.sections.map(({ id, lessons }) => {
return ({ section: +id, lessons: lessons.map(({ id }) => id) })
});
console.log('Result:', result);
.as-console-wrapper { max-height: 100% !important; }

fillter arrays of objects

i have two arrays.
const department = [
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' },
];
const models = [
{
id: '23',
name: 'model1',
departments: [{ id: '1', name: 'department1' }],
},
{
id: '54',
name: 'model2',
departments: [
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' },
],
},
];
i need to render accordions with department names and accordion details with matching models names. My question is how to filter those arrays to get models
We can map through the departments array, and add a models property that equals the models array, but filtered only to the ones that contain a matching department id.
const departments = [
{ id: "1", name: "department1" },
{ id: "2", name: "department2" },
];
const models = [
{
id: "23",
name: "model1",
departments: [{ id: "1", name: "department1" }],
},
{
id: "54",
name: "model2",
departments: [
{ id: "1", name: "department1" },
{ id: "2", name: "department2" },
],
},
];
const getDepartmentsWithModels = () => {
return departments.map((department) => {
return {
...department,
models: models.filter((model) => {
const modelDepartmentIds = model.departments.map(({ id }) => id);
return modelDepartmentIds.includes(department.id);
}),
};
});
};
console.log(getDepartmentsWithModels());
// [ { id: '1', name: 'department1', models: [ [Object], [Object] ] },
// { id: '2', name: 'department2', models: [ [Object] ] } ]```
I've built some code, which iterates over the departments. For each department it iterates the models and for each model it checks if the department is within the model departments.
const department =
[
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' }
]
const models =
[
{
id: '23',
name: 'model1',
departments: [{ id: '1', name: 'department1' }]
},
{
id: '54',
name: 'model2',
departments: [{ id: '1', name: 'department1' },{ id: '2', name: 'department2' }]
}
]
department.forEach( dep => {
console.log(`Department: ${dep.name}`)
models.forEach(model => {
if (model.departments.find(modelDep => dep.id===modelDep.id)) {
console.log(` Model: ${model.name}`)
}
})
})
If you could change your data objects, then your code could be much smoother.
I've changed your data objects slightly by just reducing the departments in a model to be an array of department id's. This code iterates over the departments. For each department it filters the models and iterates over the filtered models to output them to the console. This is lesser code and provides much better performance.
const department =
[
{ id: '1', name: 'department1' },
{ id: '2', name: 'department2' }
]
const models =
[
{
id: '23',
name: 'model1',
departments: ['1']
},
{
id: '54',
name: 'model2',
departments: ['1', '2']
}
]
department.forEach( dep => {
console.log(`Department: ${dep.name}`)
models.filter(model => model.departments.includes(dep.id)).forEach(model => {
console.log(` Model: ${model.name}`)
})
})
There are two solutions.
Using Array.reduce() --> returns an object where the key is department name and value is an array of the names of matching models:
let data1 = models.reduce((res, curr) => {
curr.departments.forEach(dep => {
if (!res[dep.name]) {
res[dep.name] = [curr.name]
} else {
if (!res[dep.name].includes(curr.name)) {
res[dep.name].push(curr.name);
}
}
})
return res;
}, {});
Using map and filter --> returns an array of kind:
[{department: [names of the models]},...]
let data2 = department.map(dep => {
let matchingModels = models.filter(model => {
return model.departments.filter(modDep => {
return modDep.name === dep.name;
}).length > 0;
}).map(mod => {
return mod.name;
});
return {
department: dep.name,
models: matchingModels
}
});

combine array of object if atleast one property is common

//this one is actual array
const data = [
{
name: 'shanu',
label: 'ak',
value: 1,
},
{
name: 'shanu',
label: 'pk',
value: 2,
},
{
name: 'bhanu',
label: 'tk',
value: 3,
},
];
>
//and this is the array that I want
let outPut =
[
{
name:'shanu',
label:['ak','pk'],
value:[1,2]
},
{
name:'bhanu',
label:['tk'],
value:[3]
}
]
You can use Array.prototype.reduce() like this:
const data = [
{
name: 'shanu',
label: 'ak',
value: 1,
},
{
name: 'shanu',
label: 'pk',
value: 2,
},
{
name: 'bhanu',
label: 'tk',
value: 3,
},
];
const output = data.reduce((prev, curr) => {
const tmp = prev.find((e) => e.name === curr.name)
if (tmp) {
tmp.label.push(curr.label)
tmp.value.push(curr.value)
} else {
prev.push({
name: curr.name,
label: [curr.label],
value: [curr.value],
})
}
return prev
}, [])
console.log(output)

Assign array values to an item in object - Javascript/React

I have an object with few items and I want to update the values of one property from array.
Object :
structure = [
{
id: 'name',
label: 'Name',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'address',
label: 'Address',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'phone',
label: 'Phone',
filterType: 'select',
filterOn: 'contains',
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
if the id is phone then I want to get the values from the array and assign it to the options instead of hard coding it.
In this object of id phone:
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
array is coming from
this.props.phoneList
label and values will be this.props.phoneList[i].name
how to loop over this and get the latest values from the array
This should keep the order of the array intact also:
const newStructure = structure.map(item => {
const isPhone = item.id === “phone”
return {
...item,
options: isPhone ? this.props.phoneList : (item.options || undefined)
}
}

Javascript function- transform from one data structure to another

I'm trying to build a JS function to convert the data structure in the form of
'start' to the form of 'expected'.
Using JS map() method, how would I do this for the following associative array-
const start = {
Clients: {
171: { id: 171, name: 'John Smith', active: false },
172: { id: 172, name: 'Jacob Jacobson', active: true },
1441: { id: 1441, name: 'Eric Ericsson', active: true },
},
Caregivers: {
1: { id: 1, name: 'John Johnson', active: true },
37: { id: 37, name: 'James Jameson', active: false },
15: { id: 15, name: 'Aaron Aaronson', active: true },
},
Doctors: {
1147: { id: 1147, name: 'Doc Docson', active: true },
},
Hospitals: {
115: { id: 115, active: false, name: "St. Mary's" },
},
Applicants: {
17345: { id: 17345, name: 'Bob Bobson', active: true },
17346: { id: 17346, name: 'Jeff Jeffson', active: false },
17347: { id: 17347, name: 'Frank Frankson', active: true },
17348: { id: 17348, name: 'Bill Billson', active: true },
},
};
needs to be converted to-
const expected = [
{ label: 'Bill Billson', value: 17348, group: 'Applicants' },
{ label: 'Bob Bobson', value: 17345, group: 'Applicants' },
{ label: 'Frank Frankson', value: 17347, group: 'Applicants' },
{ label: 'Aaron Aaronson', value: 15, group: 'Caregivers' },
{ label: 'John Johnson', value: 1, group: 'Caregivers' },
{ label: 'Eric Ericsson', value: 1441, group: 'Clients' },
{ label: 'Jacob Jacobson', value: 172, group: 'Clients' },
{ label: 'Doc Docson', value: 1147, group: 'Doctors' },
];
.map() can't be used directly on Objects; instead you'll need to use Object.keys
const start = {
Clients: {
171: { id: 171, name: 'John Smith', active: false },
172: { id: 172, name: 'Jacob Jacobson', active: true },
1441: { id: 1441, name: 'Eric Ericsson', active: true }
},
Caregivers: {
1: { id: 1, name: 'John Johnson', active: true },
37: { id: 37, name: 'James Jameson', active: false },
15: { id: 15, name: 'Aaron Aaronson', active: true }
},
Doctors: {
1147: { id: 1147, name: 'Doc Docson', active: true }
},
Hospitals: {
115: { id: 115, active: false, name: "St. Mary's" }
},
Applicants: {
17345: { id: 17345, name: 'Bob Bobson', active: true },
17346: { id: 17346, name: 'Jeff Jeffson', active: false },
17347: { id: 17347, name: 'Frank Frankson', active: true },
17348: { id: 17348, name: 'Bill Billson', active: true }
}
};
// Get an array of properties in 'start'
// then use Array.reduce() to loop over each item
const expected = Object.keys(start).reduce( (res, gKey) => {
// gKey = 'group' name
// gVal = 'group' value
let gVal = start[gKey];
// loop over each item in the 'group'
Object.keys(gVal).forEach(iKey => {
// iKey = 'group.item' name
// iVal = 'group.item' value
let iVal = gVal[iKey];
// if the value's .active property is truthy
if (iVal.active) {
// format the result as desired and add it to the result array
res.push({
label: iVal.name,
value: iKey,
group: gKey
});
}
});
// return the result array
return res;
// start the .reduce() with an empty array
}, []);
console.log(expected);
To loop over an object, you can either use a for ... in loop, or use Object.keys to get an array of keys. For ... in will include inherited properties, so you may need to manually filter them out. Object.keys only returns own properties, so there's no need to do the filtering (but it also isn't appropriate if you need inherited properties)
Example with for ... in:
for (var prop in start) {
if (start.hasOwnProperty(prop)) {
// logs out 'Clients', then 'Caregivers', then 'Doctors', then 'Hospitals', then 'Applicants'
console.log(prop);
}
}
Example with Object.keys:
//produces array ['Clients', 'Caregivers', 'Doctors', 'Hospitals', 'Applicants']
var keys = Object.keys(start);
So if you wanted to use .map, you can start with this, and fill it in to do whatever you desire:
Object.keys(start)
.map(key => {
//do something with start[key]
//perhaps you could get Object.keys(start[key]) and loop over that as well.
});
My solution without 'forEach':
function transform(data) {
Object.entries(data).map(item => Object.values(item[1])
.map(i => i.group = item[0]))
.reduce(( acc, cur ) => acc.concat(cur), [])
.filter(item => item.active === true)
.sort((a, b) => a.group - b.group)
.map(item => {
let expected = {};
expected.label = item.name;
expected.value = item.id;
expected.group = item.group;
});
return expected;
}

Categories

Resources