Using Array.map(), to extract values from array of key:value objects - javascript

I have been able to use the following code to extract values for a list of specific keys from an array of objects.
let keys = ['name', 'age'];
let employees = [
{name: 'Matt', employeeID: 123, performance: 'good', age: 21},
{name: 'Brian', employeeID: 321, performance: 'average', age: 32},
{name: 'David', employeeID: 456, performance: 'best', age: 35},
{name: 'Kevin', employeeID: 654, performance: 'poor', age: 38},
{name: 'Barrack', employeeID: 789, performance: 'super', age: 47},
];
let extracted = employees.map(object => keys.map(element => object[element]));
console.log(extracted); //result is [[Matt, 21.0], [Brian, 32.0], [David, 35.0], [Kevin, 38.0], [Barrack, 47.0]]
I have a hard time understanding conceptually how using two Array.map() methods nested within each other works like this. Can somebody walk me through how this actually works? For instance if I want to use only one Array.map() method to recreate the above, I end up with an array of truncated objects that still includes key:value pairs.
let truncated = employees.map(({name, age, ...rest}) => ({name, age}));
console.log(truncated); //result is [{age=21.0, name=Matt}, {age=32.0, name=Brian}, {age=35.0, name=David}, {name=Kevin, age=38.0}, {age=47.0, name=Barrack}]

On the first iteration of employees.map(), object is the object
{name: 'Matt', employeeID: 123, performance: 'good', age: 21}
We then execute keys.map().
On the first iteration, element is 'name', and we return object[element], which is 'Matt'. On the second iteration, element is 'age', and we return object[element], which is 21. map() combines these results into the array ['Matt', 21].
We then repeat the above for each object in the employees array, and make a list of all these results. This produces an array of arrays.

Array map takes an array of elements and transforms each element using the supplied function -
// input
[1,3,5,7].map(a => a + 10)
input
a => a + 10
output
1
1 + 10
11
3
3 + 10
13
5
5 + 10
15
7
7 + 10
17
// output
[11,13,15,17]
Now we look at it with a more simplified view -
// in // out
[ [
1, // => 11,
3, // => 13,
5, // => 15,
7, // => 17
] ]
And now expand it with a level of nesting using your objects -
[
{
name: 'Matt', // [ [
employeeID: 123, // "name", => "Matt",
performance: 'good', // "age" 21
age: 21 // ] ]
},
{
name: 'Brian', // [ [
employeeID: 321, // "name", => "Brian",
performance: 'average', // "age" 32
age: 32 // ] ]
},
{
name: 'David', // [ [
employeeID: 456, // "name", => "David",
performance: 'best', // "age" 35
age: 35 // ] ]
},
{
name: 'Kevin', // [ [
employeeID: 654, // "name", => "Kevin",
performance: 'poor', // "age" 38
age: 38 // ] ]
},
{
name: 'Barrack', // [ [
employeeID: 789, // "name", => "Barrack",
performance: 'super', // "age" 47
age: 47 // ] ]
}
]
[
[
"Matt",
21
],
[
"Brian",
32
],
[
"David",
35
],
[
"Kevin",
38
],
[
"Barrack",
47
]
]
[
["Matt",21],
["Brian",32],
["David",35],
["Kevin",38],
["Barrack",47]
]

You end up with a nested array because both maps return arrays. Your "inner" map returns an array of values based on the keys array, and that is returned to the "outer" map that's been iterating over the array of each object, which also returns an array.
// Create a new array by mapping over each object
employees.map(object => {
// For each key in the keys array return a
// new array of only those values of the
// properties of the object that match the key
return keys.map(element => object[element]);
});

let keys = ['name', 'age'];
let employees = [
{name: 'Matt', employeeID: 123, performance: 'good', age: 21},
{name: 'Brian', employeeID: 321, performance: 'average', age: 32},
{name: 'David', employeeID: 456, performance: 'best', age: 35},
{name: 'Kevin', employeeID: 654, performance: 'poor', age: 38},
{name: 'Barrack', employeeID: 789, performance: 'super', age: 47},
];
let extracted = employees.flatMap(object => keys.map(element => object[element]));
console.log(extracted);
What you are looking for should be a flatMap

Related

Map + filter - Showing people that have < 18 years and abbreviate names

I wanted to be able to transform the age into a single array, so I would already know how to filter, then apply the mapping to only show people over 18 years old, in addition, to present the abbreviated names of the people.
Example:
name: "Raul", age: 27,
name: "Jose", age: 14,
name: "Maria", age: 52,
name: "Jesus", age: 17,
name: "Neo", age: 2
[Ra, Ma] -> Those are above 18, and their names go abbreviated
Here what i tried to do:
const amantesGatos = {
name: "Raul", age: 27,
name: "Jose", age: 14,
name: "Maria", age: 52,
name: "Jesus", age: 17,
name: "Neo", age: 2
};
// this needs to be filtered
const idade = amantesGatos.age
//i tried to destructuring this array
const nomeAbrev = [amantesGatos.map(n=>n[0] + n[1])]
//Tried to abbreviated names
//Filter above 18
const array = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 444, 17];
function above18(num) {
for (let i = 18; num < i; i--) {
if (num < i) {
return false;
}
}
return num;
}
console.log(array.filter(above18));
If I'm understanding correctly the desired outcome is [Ra, Ma]?
If so you can .filter.map.
const peeps = [
{name: "Raul", age: 27,},
{name: "Jose", age: 14,},
{name: "Maria", age: 52,},
{name: "Jesus", age: 17,},
{name: "Neo", age: 2}
]
const ofAgePeeps = peeps.filter(({age}) => age > 18)
const shortNames = ofAgePeeps.map(({name}) => name.substring(0,2))
You can also chain these...
peeps.filter(({age}) => age > 18).map(({name}) => name.substring(0,2))
That said your amantesGatos is an object with a bunch of duplicate keys and not an array. Which means it's really an object with only the last name and age. For example...
const obj = {
name: 'Tom', age: 2, name: 'Bob', age: 100
}
console.log(obj) // {name: 'Bob', age: 100}
You can do as following
let users = [
{ name: "Raul", age: 27,},
{name: "Jose", age: 14,},
{name: "Maria", age: 52,},
{name: "Jesus", age: 17,},
{name: "Neo", age: 2},
]
let data = users.filter(user => user.age > 18).map(user => user.name.slice(0, 2))
data would be [ 'Ra', 'Ma' ]

Push multiple objects to an already initialized, empty object array

People is my model, data is my new information, and the forEach is how I am trying to insert the new data into my model, but formatted to only the information I care about
people = [{name: '', age: 0}];
data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
data.forEach(person => {
people.push({
name: person.name,
age: person.age,
});
});
However, the result I get is this:
people = [
{name: '', age: 0},
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
I'm trying to have the object array look like this instead:
people = [
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
However, I would like to know if theres a way to do it without an extra line of code (like popping the first element), and if theres a way to do it in one command? If not, I am open to suggestions. Thank you!
You're using the original array and not only that but also you're mutating the array.
You can use the function Array.prototype.map in order to generate a new array with the desired data.
const people = [{name: '', age: 0}];
const data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
const result = data.map(person => ({
name: person.name,
age: person.age,
}));
console.log(result);
You can also keep the desired keys and by using the functions Array.prototype.map and Array.prototype.reduce you can build the expected result:
const model = ["name", "age"];
const data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
const result = data.map(person => model.reduce((r, m) => ({...r, [m]: person[m]}), {}), []);
console.log(result);
Just in case you need to implement different person models, you can dinamically create the objects like this
peopleModel = [{ name: "", age: 0 }];
data = [
{ id: "123", name: "Bob", lastName: "Guy", age: 40 },
{ id: "321", name: "Michael", lastName: "Park", age: 20 },
];
const keysArr = Object.keys(peopleModel[0]);
const totalKeys = keysArr.length;
const people = data.reduce((acc, personObj) => {
const obj = {};
keysArr.forEach((key) => {
if (personObj[key]) {
obj[key] = personObj[key];
}
});
acc.push(obj);
return acc;
}, []);
console.log(people);
/* logs [
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
*/
but if you need a different model like
peopleModel = [{ name: "", age: 0, lastName: "" }]
you will get for the log the following:
[
{name: 'Bob', age: 40, lastName: 'Guy'},
{name: 'Michael', age: 20, lastName: 'Park'}
];
that way you do not need to hardcode the keys

How to flat array of objects which can contain nested objects in my case

I have a data with structure like this:
const arr1 = [
{
name: 'a',
subObjects: [
{ name: 'a1', age: 10 },
{ name: 'a2', age: 12 },
],
},
{ name: 'b', age: 23 },
{
name: 'c',
subObjects: [
{ name: 'c1', age: 30 },
{ name: 'c2', age: 32 },
],
},
...
];
So, the array contains an array of objects, some objects also contain nested level object subObjects which contains the same structure as parent. Overall some 1st level object in array can have maximum two levels of nest (like above example shows).
Now, I need to have an array that gather all names of objects from above array, something like:
[
{ name: 'a' },
{ name: 'a1' },
{ name: 'a2' },
{ name: 'b' },
{ name: 'c' },
{ name: 'c1' },
{ name: 'c2' },
];
This is what I tried:
const arr1 = [
{
name: 'a',
subObjects: [
{ name: 'a1', age: 10 },
{ name: 'a2', age: 12 },
],
},
{ name: 'b', age: 23 },
{
name: 'c',
subObjects: [
{ name: 'c1', age: 30 },
{ name: 'c2', age: 32 },
],
},
];
const arr2 = arr1.map((obj) => {
return obj.subObjects ? obj.subObjects.flat() : obj.name;
});
console.log(arr2.flat());
But the output lost the 1st level object names for those who has nested objects. So, what is the best way to achieve what I need?
You could use a recursive flatMap to do it (with a little help from the spread oparator!):
const arr1 = [{name: 'a', subObjects:[{name: 'a1', age: 10}, {name: 'a2', age: 12},]}, {name: 'b', age: 23}, {name: 'c', subObjects:[{name: 'c1', age: 30}, {name: 'c2', age: 32},]}];
const recursiveFlat = (arr) => arr.flatMap(
a => a.subObjects
? [{name: a.name}, ...recursiveFlat(a.subObjects)]
: {name: a.name});
console.log(recursiveFlat(arr1));
This will work with any depth of nesting.

JavaScript ungroup data in object

I am trying to flatten the below data structure, I feel like there must be a good way fo doing this without manually iterating through each element to manually build it.
[{
group: 'abc',
data: [{
name: 'John',
age: 10
}, {
name: 'Alice',
age: 15
}]
}, {
group: 'def',
data: [{
name: 'Scott',
age: 20
}, {
name: 'Tamar',
age: 25
}]
}]
and I wanted it to be something like this instead (so the group is alongside the data):
[{
group: 'abc',
name: 'John',
age: 10
}, {
group: 'abc',
name: 'Alice',
age: 15
}, {
group: 'def',
name: 'Scott',
age: 20
}, {
group: 'def',
name: 'Tamar',
age: 25
}]
Any ideas would be appreciated.
const a = [
{group: 'abc', data: [{name: 'John', age: 10}, {name: 'Alice', age: 15}]},
{group: 'def', data: [{name: 'Scott', age: 20}, {name: 'Tamar', age: 25}]}
];
const flat = a.flatMap(({group, data}) => data.map(o => Object.assign({group}, o)));
console.log(flat)
// Unmodified original Array:
console.log(a)
MDN Array.prototype.flatMap()
MDN Array.prototype.map()
MDN Object.assign()
Array#reduce would be helpful.
const a = [{group:'abc',data:[{name:'John',age:10},{name:'Alice',age:15}]},{group:'def',data:[{name:'Scott',age:20},{name:'Tamar',age:25}]}];
const r = a.reduce((s, { group, data }) =>
(data.forEach((o) => s.push({ ...o, group })), s), []);
console.log(r);
Iterate the array with Array.flatMap(), then map each group, and construct the new objects using object spread:
const arr = [{"group":"abc","data":[{"name":"John","age":10},{"name":"Alice","age":15}]},{"group":"def","data":[{"name":"Scott","age":20},{"name":"Tamar","age":25}]}]
const result = arr.flatMap(({ group, data }) => data.map(o => ({ group, ...o })))
console.log(result)

Create an array of objects?

arr = [
men: {name: "john", age:"30"},{name: "john2", age:"31"},
women: {name: "kim", age:"10"},{name: "karen", age:"33"}
]
I'm looking to create an array with properties men and women, and each of those will have a bunch of objects. How can I do that in JS?
First create object then array in it, so like this you can manage your data.
let arr = {
men: [
{name: 'john', age: 30},
{name: 'john2', age:33}
],
women: [
{name: 'kim', age: 30},
{name: 'kim2', age:33}
],
}
console.log( arr.men[0].name );
just extend the value in the men or women array.
Thanks!
You need an object in order to achieve this. After this, you will be able to manage the people object just anyhow you want.
var people = {
men: [
{name: "man1", age: 30},
{name: "man2", age: 31},
],
women: [
{name: "woman1", age: 30},
{name: "woman2", age: 31},
]
}
// Add to men
people.men.push({"man3", age: 32})
// Add to women
people.women.push({"woman3", age: 32});
// Print the people object
console.log(JSON.stringify(people, null, 2)); // pretty format

Categories