Flatten objects in array - javascript

Hey folks I am getting an array of objects from a response. I need to flatten all of the students objects to simply studentName but not certain how. Any help would be greatly appreciated.
Example Array:
[
{
students: {id: '123456', name: 'Student Name'},
active: true
},
{
students: {id: '123456', name: 'Student Name'},
active: true
}
]
What I am trying to do:
[
{
studentName: 'Student Name',
active: true
},
{
studentName: 'Student Name',
active: true
}
]

[
{ students: {id: '123456', name: 'Student Name'}, active: true },
{ students: {id: '123456', name: 'Student Name'}, active: true }
].map(e => ({studentName: e.students.name, active: e.active}))

You can create and return a new array of result using map as:
const arr = [
{
students: { id: "123456", name: "Student Name" },
active: true,
},
{
students: { id: "123456", name: "Student Name" },
active: true,
},
];
const result = arr.map(({ students, ...rest }) => ({
...rest,
studentName: students.name,
}));
console.log(result);

You can loop through the array and set each item's students property to the name property of the students property:
const arr = [
{students: {id: '123456', name: 'Student Name'},active: true},
{students: {id: '123456', name: 'Student Name'},active: true}
]
arr.forEach(e => e.students = e.students.name)
console.log(arr)

map over the data and return a new object on each iteration.
const data=[{students:{id:"123456",name:"Student Name"},active:!0},{students:{id:"123456",name:"Student Name"},active:!0}];
const out = data.map(obj => {
// Destructure the name and active properties
// from the object
const { students: { name }, active } = obj;
// Return the new object
return { studentName: name, active };
});
console.log(out);

You can use the .map() method to rebuild the objects in the array with whatever structure you need.
const arr = [
{
students: {id: '123456', name: 'Student Name'},
active: true
},
{
students: {id: '123456', name: 'Student Name'},
active: true
}
];
function flatten(array) {
return arr.map(({ students, active }) => {
return {
studentName: students.name,
active,
};
});
}
console.log(flatten(arr));

try this
let student =[
{
students: {id: '123456', name: 'Student Name'},
active: true
},
{
students: {id: '123456', name: 'Student Name'},
active: true
}
];
console.log(student.map(x=> ({ studentName: x.students.name,active: x.active })));

Related

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
}
});

Merge 3 arrays by matching ID's [duplicate]

This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed 1 year ago.
I have a small exercise, to merge three arrays into one array by matching ID's, I'd like to add the likes and comments array into the posts array how would I go about this?
const posts =
[ { _id: 1
, message: 'this is post one'
, likes: [ { id: 1111 } , { id: 2222 } ]
, comments: [ { id: 3333 } , { id: 4444 } ]
}
]
const comments =
[ { id: 3333, message: 'this is comment 1' }
, { id: 4444, message: 'this is comment 2' }
]
const likes =
[ { id: 1111, user: 'Peter' }
, { id: 2222, user: 'John' }
]
expected output:
newArray =
[ { _id: 1
, message: 'this is post one'
, likes:
[ { id: 1111, user: 'Peter'}
, { id: 2222, user: 'John'} ]
, comments:
[ { id: 3333, message: 'this is comment 1'}
, { id: 4444, message: 'this is comment 2'}
] } ]
Here is a similar approach I've used when working with two arrays:
const
arr1 = [{ groupId: "Category", options: [{ name: "cookies", id: 1111 }, { name: "tv", id: 2222 }] }, { groupId: "Brand", options: [{ name: "random", id: 3333 }] }, { groupId: "Price", options: [{ name: "random2", id: 4444 }] }],
arr2 = [{ id: 1111, url: "/test", other: 'other-prop' }, { id: 2222, url: "/test1" }, { id: 3333, url: "/test2" }],
mergeById = (arr1, arr2) =>
arr1.map(({ options, ...rest }) => (
{
...rest,
options: options.map(option => (
{
...option,
...arr2.find(_option => _option.id === option.id)
}
))
}
));
const merged = mergeById(arr1, arr2);
console.log(JSON.stringify(merged, null, 2));
const newPosts = posts.map(post => ({
...post,
likes: likes.filter(like => post.likes.map(like => like.id).includes(like.id)),
comments: comments.filter(comment => post.comments.map(comment => comment.id).includes(comment.id)),
}))
console.log(newPosts)

How to re-map an array to use in Ant Design Tree

I have this code structure:
const data = [
{
name: 'Lebron',
sports: 'Basketball',
},
{
name: 'Durant',
sports: 'Basketball',
},
{
name: 'Federrer',
sports: 'Tennis',
},
{
name: 'Nadal',
sports: 'Tennis',
},
];
and I'm trying to transform it into this:
const treeData = [
{
title: 'Select All',
key: 'All',
children: [
{
title: 'Basketball',
key: 'Basketball',
children: [
{
title: 'Lebron',
key: 'Lebron',
},
{
title: 'Durant',
key: 'Durant',
},
],
},
{
title: 'Tennis',
key: 'Tennis',
children: [
{
title: 'Federrer',
key: 'Federrer',
},
{
title: 'Nadal',
key: 'Nadal',
},
],
},
],
},
];
to use in Ant Design Tree link.
Right now my plan is to get all the sports like this:
let sports = data.map(({ sports }) => sports);
sports = [...new Set(sports)];
but after that I have no idea on what should be my next step to achieve the treeData
You can use .reduce() to accumulate all sports to a Map, where each sport is a key and each value for the sport is an array of associated names. Once you have built the Map, you can use Array.from() to convert your map into your desired children array. This can be done by providing a mapping function as the second argument to Array.from(), and using it to convert each entry ([key, value]) pair to an object of your desired structure.
See example below:
const data = [ { name: 'Lebron', sports: 'Basketball', }, { name: 'Durant', sports: 'Basketball', }, { name: 'Federrer', sports: 'Tennis', }, { name: 'Nadal', sports: 'Tennis', }, ];
const children = Array.from(data.reduce((m, {name, sports}) =>
m.set(sports, [...(m.get(sports) || []), name])
, new Map), ([key, arr]) => ({title: key, key, children: arr.map(title => ({title, key: title}))}));
const treeData = [{title: 'Select All', key: 'All', children}];
console.log(treeData);
const data = [
{
name: 'Lebron',
sports: 'Basketball',
},
{
name: 'Durant',
sports: 'Basketball',
},
{
name: 'Federrer',
sports: 'Tennis',
},
{
name: 'Nadal',
sports: 'Tennis',
},
];
const dataMap: Record<string, string[]> = {};
data.forEach(({ name, sports }) => {
dataMap[sports] ??= []
dataMap[sports].push(name)
})
const treeData = [{
title: 'Select All',
key: 'All',
children: Object.entries(dataMap).map(([sport, names]) => ({
title: sport,
key: sport,
children: names.map(name => ({
title: name,
key: name
}))
}))
}]
Here's a two-steps way of get the children of your final object:
First, use a reduce to create an object of sports/children, where children matches what you have in your final output:
const middle = data.reduce((transformed, item) => {
if (!transformed[item.sports]) {
transformed[item.sports] = [];
}
transformed[item.sports].push({
title: item.name,
key: item.name
});
return transformed;
}, {});
Then map the results of the reduce function to reshape the object:
const results = Object.entries(middle).map(([key, children]) => ({
title: key,
key,
children
}));

Filter array within array using single key = single value and single key = multiple value

const personData = {
personID: 1234567,
personList: [{
name: ['name1', 'name2'],
address: false,
pin: 12345
},
{
name: ['name1', 'name2', 'name3'],
address: true,
pin: 45678
},
{
name: ['name1'],
address: false,
pin: 12345
},
]
};
const keys = ['name', 'address', 'pin']
const values = ['name1', 'name2', false, 12345]
let personDataArr = personData.personList.filter(function(e) {
return keys.every(function(a) {
return e[a] &&
e[a].length > 0 ? values.every(x => e[a].includes(x)) : values.includes(e[a])
});
});
console.log(personDataArr);
The code shows the person Data object which includes the information like name, address and pin.
I tried using filter but I am not getting a properly filtered result.
I am executing the code I am getting null, but I am expecting the first person List object.
Could some one take a look into the code and modify if possible and send me the expected result as output.
I will suggest you to have your key value as an object instead of two different arrays
const {personList} = {personID: 1234567,personList: [{name: ['name1', 'name2'],address: false,pin: 12345},{name: ['name1', 'name2', 'name3'],address: true,pin: 45678},{name: ['name1'],address: false,pin: 12345},]};
const filterBy = { name:['name1', 'name2'],address: false,pin:12345 }
let personDataArr = personList.filter(e => {
return Object.keys(e).every(key => {
return Array.isArray(e[key]) ? filterBy[key].every(value=> e[key].includes(value))
: e[key] === filterBy[key]
})
})
console.log(personDataArr);
It will get really hard to reliably filter with the filter criteria you've provided. How should the code determine which of the values are needed for every given key? Not possible.
It'll be better to provide the values in a well structured way, such as
const filterCriteria = [
{
key: 'name',
values: ['name1', 'name2']
}, {
key: 'address',
value: false
}, {
key: 'pin',
value: 12345
}
];
const getPerson = (list, criterias) =>
list.filter(element =>
criterias.every(criteria =>
element.hasOwnProperty(criteria.key) &&
criteria.hasOwnProperty('value') ?
element[criteria.key] === criteria.value :
(criteria.values.every(value => element[criteria.key].includes(value))) && element[criteria.key].every(value => criteria.values.includes(value)))
);
console.log(getPerson(personData.personList, filterCriteria));
<script>
const personData = {
personID: 1234567,
personList: [
{
name: ['name1', 'name2'],
address: false,
pin: 12345
},
{
name: ['name1', 'name2', 'name3'],
address: true,
pin: 45678
},
{
name: ['name1'],
address: false,
pin: 12345
},
]
};
const filterCriteria = [
{
key: 'name',
values: ['name1', 'name2']
}, {
key: 'address',
value: false
}, {
key: 'pin',
value: 12345
}
];
</script>

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