Group array of objects by different keys - javascript

I have an array of objects structured as below:
const myArr = [
{ name: "John", surname: "Smith", age: 18},
{ name: "Steve", surname: "Jones", age: 23},
{ name: "Mark", surname: "Green", age: 45},
{ name: "Anne", surname: "Williams", age: 34}
]
And I would like to group it like so:
[
{name: ["John", "Steve", "Mark", "Anne"]},
{surname: ["Smith", "Jones", "Green", "Williams"]},
{age: [18, 23, 45, 34]}
]
What's the best way? Tried with reduce() but no luck.

Assuming you know all objects have exactly the same keys, you can use Object.keys() function on the first element of the array, then iterate over the keys to create your objects
Object.keys(myArr[0]).map(key => {
const obj = {}; // Probably a better way to do that
obj[key] = myArr.map(item => item[key]);
return obj;
});

Nastier but shorter.
Object.keys(myArr[0]).map(key => ({ [key]: myArr.map(item => item[key]) }));

You could iterate the array, get all entries from the object and push to the array with the wanted key.
const
array = [{ name: "John", surname: "Smith", age: 18 }, { name: "Steve", surname: "Jones", age: 23 }, { name: "Mark", surname: "Green", age: 45 }, { name: "Anne", surname: "Williams", age: 34 }],
result = array.reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => (r[k] ??= []).push(v));
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Use forEach and build an object with keys and aggregate values in array.
Now, create the array from above object entries.
const process = (arr) => {
const res = {};
arr.forEach((item) =>
Object.entries(item).forEach(([key, value]) =>
(res[key] ??= []).push(value)
)
);
return Object.entries(res).map(([key, value]) => ({ [key]: value }));
};
const myArr = [
{ name: "John", surname: "Smith", age: 18 },
{ name: "Steve", surname: "Jones", age: 23 },
{ name: "Mark", surname: "Green", age: 45 },
{ name: "Anne", surname: "Williams", age: 34 },
];
console.log(process(myArr));

Related

How to move similar profession people into newly created object (result) in javascript

I have one quick question, I want to move all similar professional people into a newly created object (result), I have written the code but all values are not moved.
const data = [
{
Name: 'Smith',
age: 25,
profession: 'Banker'
},
{
Name: 'Alex',
age: 28,
profession: 'IT'
},
{
Name: 'John',
age: 31,
profession: 'Banker'
},
{
Name: 'Harry',
age: 26,
profession: 'Nurse'
},
];
const result = {};
My code is here ...
const data = [ { Name: "Smith", age: 25, profession: "Banker" }, { Name: "Alex", age: 28, profession: "IT" }, { Name: "John", age: 31, profession: "Banker" }, { Name: "Harry", age: 26, profession: "Nurse" } ];
const result = {};
data.forEach(({ Name, age, profession }) => {
result[profession] = { Name, age };
});
console.log(result);
CodePen:
https://codepen.io/Sandy4405/pen/wvmLaJX
Expanding on my comment above, the inside of your forEach should be:
data.forEach(({ Name, age, profession }) => {
if (Array.isArray(result[profession])) {
result[profession].push({ Name, age })
} else {
result[profession] = [{ Name, age }]
}
});
You need to create a nested JSON, which means an array of objects for a similar profession. While iterating, create an array for each profession and use .push() to add the objects. The code would look like below
data.forEach(({Name,age,profession}) => {
result[profession] = result[profession] || [];
result[profession].push({Name,age});
});
Working Version:
const data = [{
Name: "Smith",
age: 25,
profession: "Banker"
},
{
Name: "Alex",
age: 28,
profession: "IT"
},
{
Name: "John",
age: 31,
profession: "Banker"
},
{
Name: "Harry",
age: 26,
profession: "Nurse"
}
];
const result = {};
data.forEach(({
Name,
age,
profession
}) => {
result[profession] = result[profession] || [];
result[profession].push({
Name,
age
});
});
console.log(result);
After the first person with a given profession is encountered, each subsequent person with the same profession will overwrite the previous one. You should instead create an array and push each of the people with the same profession to that array.
First, we'll check if the current profession has been encountered before.
If it hasn't, we'll create an empty array to hold all of the people with this profession.
if (!(profession in result)) {
result[profession] = []
}
Then, since the array is now guaranteed to exist for this profession, we can push to our new array the current person. The next time this profession is encountered, our first check will be skipped and we'll just push the next person onto the array.
result[profession].push({
Name,
age
})
Full example:
const data = [{
Name: "Smith",
age: 25,
profession: "Banker"
}, {
Name: "Alex",
age: 28,
profession: "IT"
}, {
Name: "John",
age: 31,
profession: "Banker"
}, {
Name: "Harry",
age: 26,
profession: "Nurse"
}]
const result = {}
data.forEach(({
Name,
age,
profession
}) => {
if (!(profession in result))
result[profession] = []
result[profession].push({
Name,
age
})
})
console.log(result)
As filipe said in his comment, Your current code is just assigning the values into an object which results in maintaining the single value against keys. To group the same profession values into a respective profession key, You have to do something like this :
const data = [ { Name: "Smith", age: 25, profession: "Banker" }, { Name: "Alex", age: 28, profession: "IT" }, { Name: "John", age: 31, profession: "Banker" }, { Name: "Harry", age: 26, profession: "Nurse" } ];
const result = {};
data.forEach(({ Name, age, profession }) => {
result[profession] ? result[profession].push({ Name, age }) : result[profession] = [{ Name, age }];
});
console.log(result);

Compare two array of objects based on only matching properties

I have two array of objects
this.originalData = [
{age: 27, name: "sachin", id: 1, sex: "male", dept: "angular"},
{age: 22, name: "pooja", id: 2, sex: "female", dept: "java"},
{age: 50, name: "john", id: 3, sex: "male", dept: "sales"}
]
this.updatedData = [
{id: 1, name: "sachin", age: 25, sex: "male"},
{id: 2, name: "pooja", age: 22, sex: "female"},
{id: 3, name: "john", age: 50, sex: "male"}
]
As we can see the order and number of properties is different in both the arrays. Here, how can I do the comparison for only matching properties whether any of it is changed. In the above example, I need to get the object with id 1 from updatedData as the age property is changed from 27 to 25 when compared with originalData. The properties which are not matching can be ignored.
I tried like below but it is not working due to the differences
if(JSON.stringify(this.updatedData) !== JSON.stringify(this.originalData)) {
console.log('changed!');
}
Please suggest. Thanks.
const originalData = [
{ age: 27, name: "sachin", id: 1, sex: "male", dept: "angular" },
{ age: 22, name: "pooja", id: 2, sex: "female", dept: "java" },
{ age: 50, name: "john", id: 3, sex: "male", dept: "sales" }
]
const updatedData = [
{ id: 1, name: "sachin", age: 25, sex: "male" },
{ id: 2, name: "pooja", age: 22, sex: "female" },
{ id: 3, name: "john", age: 50, sex: "male" }
]
const output = updatedData.filter(uData => {
const commonDataRow = originalData.find(oData => oData.id === uData.id); /** filter out common entry between both arrays based on id */
const allPropertiesAreSame = Object.keys(commonDataRow).every(oDataEntry => /** iterate through the list of properties of common entry */
/**
* if the updatedData object has the properties, check if the values are same for both the objects and return appropriately,
* else ignore the property (by returning false)
*/
uData.hasOwnProperty(oDataEntry) ?
commonDataRow[oDataEntry] === uData[oDataEntry] : true
);
/** if all properties are same, return false (as we desire to filter out those entries which have at least one unmatching property) */
return !allPropertiesAreSame;
});
/**
* print the output
* the output will contain the list of objects matching the above criteria
* format it to get the list of ID's
*/
console.log(output);
The following code-snippet gives you all the items, where data has changed (ignoring keys which do not exist in either of them).
let originalData = [
{age: 27, name: "sachin", id: 1, sex: "male", dept: "angular"},
{age: 22, name: "pooja", id: 2, sex: "female", dept: "java"},
{age: 50, name: "john", id: 3, sex: "male", dept: "sales"}
];
let updatedData = [
{id: 1, name: "sachin", age: 25, sex: "male"},
{id: 2, name: "pooja", age: 22, sex: "female"},
{id: 3, name: "john", age: 50, sex: "male"}
];
let changedList = [];
originalData.map((item)=> {
let temp = (updatedData.filter((x) => item.id === x.id ))[0];
let same = true;
if((item.age && temp.age) && (item.age !== temp.age)) {same = false}
if((item.name && temp.name) && (item.name !== temp.name)) {same = false}
if((item.sex && temp.sex) && (item.sex !== temp.sex)) {same = false}
if((item.dept && temp.dept) && (item.dept !== temp.dept)) {same = false}
if(same === false) {changedList.push(item)};
console.log(same);
});
console.log(changedList);

Filter an array of objects returns empty array

I hae the following array of objects:
arr = [
{
name: "john",
age: 24,
gender: "male"
},
{
name: "jane",
age: 27,
gender: "female"
},
{
name: "joe",
age: 29,
gender: "male"
}
]
I'm trying to filter the name and age property into a new array. I tried this:
const newFields = arr.filter((item) => {
return (
item.name && item.age
);
});
But for some reason newFields returns an empty array.
Instead of .filter() use .map()
const arr = [
{
name: "john",
age: 24,
gender: "male"
},
{
name: "jane",
age: 27,
gender: "female"
},
{
name: "joe",
age: 29,
gender: "male"
}
];
const newFields = arr.map(item => {
return {
name: item.name,
age: item.age
}
});
console.log(newFields)
This can be a one liner too with the arrow function and Parameter Context Matching
const newFields = arr.map(({ name, age }) => ({ name, age }));
Your solution's result can not be empty but the original array, because in this case the return value of your filter function will be always true (every item has the name and age property) which doesn't filter anything from the original arr variable.
If you are creating a new array with a subset of the original - then you can iterate over the array and push the desired elements into its own array.
That said if all you are trying to get is the name and age of the existing array - why do you need to create a separate array? - you can just iterate over the original array and reference only the desired values from each item.
let arr = [
{
name: "john",
age: 24,
gender: "male"
},
{
name: "jane",
age: 27,
gender: "female"
},
{
name: "joe",
age: 29,
gender: "male"
}
]
let newArr = [];
arr.forEach(function(item) {
newArr.push({name:item.name, age:item.age})
});
console.log(newArr); // gives [{"name": "john","age": 24},{"name": "jane","age": 27},{"name": "joe","age": 29}]

Iterating through an array containing objects using a function and a parameter

I'd like to create a function that iterates through an array containing separate objects with name, surname and age properties. The function should take a parameter "name" and return the name, surname and age in the console.
How would I do this? I've looked at some other questions but can't seem to figure out how to do it. I've created this so far...
var people = [
{ name: "Sue", surname: "Beckett", age: 50},
{ name: "Bill", surname: "Borough", age: 44},
{ name: "Janet", surname: "Jupp", age: 23},
{ name: "Peter", surname: "Pepper", age: 21},
{ name: "Samantha", surname: "Salad", age: 17}
];
function person(name) {
// code here
}
person(sue)
Simply use Array#find() method like this:
function person(name) {
return people.find(function(p) {
return p.name == name;
});
}
console.log(person("Samantha"));
Demo:
var people = [{
name: "Sue",
surname: "Beckett",
age: 50
},
{
name: "Bill",
surname: "Borough",
age: 44
},
{
name: "Janet",
surname: "Jupp",
age: 23
},
{
name: "Peter",
surname: "Pepper",
age: 21
},
{
name: "Samantha",
surname: "Salad",
age: 17
}
];
function person(name) {
return people.find(function(p) {
return p.name == name;
});
}
console.log(person("Samantha"));
console.log(Object.values(person("Samantha")));
Note:
Make sure you pass the name as a string when you call your method, passing just sue without "" will assume you have a variable called sue.
Note that you can use Object.values() to show only the values of
the object properties, instead of the whole object.
Simply write :
console.log(Object.values(person("Samantha")));
var people = [
{ name: "Sue", surname: "Beckett", age: 50},
{ name: "Bill", surname: "Borough", age: 44},
{ name: "Janet", surname: "Jupp", age: 23},
{ name: "Peter", surname: "Pepper", age: 21},
{ name: "Samantha", surname: "Salad", age: 17}
];
function person(name) {
for (var key in people) {
var person = people[key];
if (name === person.name) {
console.log(person);
}
}
}
person("Sue"); // string always needs quotes: " or ' character
You could filter the array by checking the lower case value of name property and name variable.
function person(name) {
people
.filter(o => o.name.toLowerCase() === name.toLowerCase())
.forEach(({ name, surname, age}) => {
console.log('name:', name);
console.log('suname:', surname);
console.log('age:', age);
});
}
var people = [{ name: "Sue", surname: "Beckett", age: 50 }, { name: "Bill", surname: "Borough", age: 44 }, { name: "Janet", surname: "Jupp", age: 23 }, { name: "Peter", surname: "Pepper", age: 21 }, { name: "Samantha", surname: "Salad", age: 17 }];
person('sue');
Using filter:
var people = [
{ name: "Sue", surname: "Beckett", age: 50},
{ name: "Bill", surname: "Borough", age: 44},
{ name: "Janet", surname: "Jupp", age: 23},
{ name: "Peter", surname: "Pepper", age: 21},
{ name: "Samantha", surname: "Salad", age: 17}
];
function person(personName) {
var user = people.filter(function (user) {
return (user.name.toLowerCase() == personName.toLowerCase());
});
return user[0] !== undefined ? user[0] : 'not found';
}
console.log(person('sue'));
var people = [
{ name: "Sue", surname: "Beckett", age: 50},
{ name: "Bill", surname: "Borough", age: 44},
{ name: "Janet", surname: "Jupp", age: 23},
{ name: "Peter", surname: "Pepper", age: 21},
{ name: "Samantha", surname: "Salad", age: 17}
];
function person(name) {
people.map((data,index)=>{
if(data.name == name)
{
console.log(data.name);
console.log(data.surname);
console.log(data.age);
return;
}
})
}
person("Sue");

Remove array duplicates by property javascript

I have a list of objects:
[{name: "bob", age: "14"}, {name: "bob", age: "16"}, {name: "sue", age: "21"}]
I need a simple way to filter out duplicates with regard to the name property, so:
[{name: "bob", age: "14"}, {name: "sue", age: "21"}]
There seem to be quite a few array duplicate removal questions, but not any based on a property. It can ignore all other fields.
Iterate the array, place all name values in a hash and skip objects whose name is already in the hash:
filterBy = function(ary, prop) {
var seen = {};
return ary.filter(function(item) {
var key = item[prop];
if(seen[key] === 1)
return false;
seen[key] = 1;
return true;
});
}
//
a = [{name: "bob", age: "14"}, {name: "bob", age: "16"}, {name: "sue", age: "21"}]
b = filterBy(a, 'name');
console.log(b);
ES6 version:
filterBy = function(ary, prop) {
var seen = new Set();
return ary.filter(item => !seen.has(item[prop]) && seen.add(item[prop]));
}
a = [{name: "bob", age: "14"}, {name: "bob", age: "16"}, {name: "sue", age: "21"}]
b = filterBy(a, 'name');
console.log(b);
You can do it with 2 for loops as follows. All you have to do is, keeping a result array and every time you insert into it, check whether the name attributes are equal.
function findDuplicate(){
var array= [{name: "bob", age: "14"}, {name: "bob", age: "16"}, {name: "sue", age: "21"}];
var result=[];
for(x in array){
var found=false;
for(y in result){
if(result[y].name.localeCompare(array[x].name)==0){
found=true;
}
}
if(!found){
result.push(array[x]);
}
}
console.log(result);
}
You could do this with forEach and thisArg param.
var data = [{name: "bob", age: "14"}, {name: "bob", age: "16"}, {name: "sue", age: "21"}];
var result = [];
data.forEach(function(e) {
if (!this[e.name]) {
this[e.name] = e;
result.push(this[e.name]);
}
}, {});
console.log(result)
Or with forEach and map()
var data = [{name: "bob", age: "14"}, {name: "bob", age: "16"}, {name: "sue", age: "21"}], result =[];
data.forEach(function(e) {
if(result.map(a => {return a.name}).indexOf(e.name) == -1 ) result.push(e);
});
console.log(result)
You could use Array#filter and a this object for marking, if the same name is already filtered.
var array = [{ name: "bob", age: "14" }, { name: "bob", age: "16" }, { name: "sue", age: "21" }],
filtered = array.filter(function (a) {
if (!this[a.name]) {
this[a.name] = true;
return true;
}
}, Object.create(null));
console.log(filtered);
For the straightforward comparison in the Q., there are some
good answers here. If you want to provide a custom comparison
function that will work on e.g. object values, or that uses
a RegExp, then take a look at the following.
var dedupwhen = function(fn, list){
if(list[0] === undefined){
return [];
}
// Join the first item to the remainder that has had the first
// item filtered out (according to fn) and then been
// deduplicated itself.
return [list[0]].concat(dedupwhen(fn, list.slice(1).filter(function(item){
return !fn(list[0], item);
})));
};
var similarname = function(x,y){
return RegExp('^' + x.name + '$', 'i').test(y.name);
};
var list = [
{name: 'Sue', age: 44},
{name: 'Bob', age: "14"},
{name: 'bob', age: "16"},
{name: 'sue', age: "21"}
];
console.log(dedupwhen(similarname, list));

Categories