How to group array of objects by certain property values - javascript

I have a two arrays.
One array with strings which contains names
let companies = ['Google', 'Coca Cola,' 'Jonson & Jonson',];
And another array contains objects with people
let employees = [
{name: 'Alina' company: 'Google', id : 1},
{name: 'Vika' company: 'Coca Cola', id : 2},
{name: 'Alex' company: 'Jonson & Jonson', id : 3},
{name: 'Vlad' company: 'Google', id : 4},
{name: 'Fibi' company: 'Coca Cola', id : 5},
{name: 'Joey' company: 'Google', id : 6},
]
And my task is to group those people by names
const groups = [
{'Google': [
{name: 'Alina' company: 'Google', id : 1},
{name: 'Vlad' company: 'Google', id : 4},
]},
'Jonson & Jonso': [
{name: 'Alex' company: 'Jonson & Jonson', id : 3},
]},
...
]
Maybe anyone knows how to do it the simplest way and without extra iterations for JS ?
I could use a nested loops but it would be too complicated.
Maybe it's possible to do with lodash ?
Also please note that string keys for company names may have spaces.
Will be very grateful for any advices.

A back to the future answer :
Not yet supported by lot of browsers but will come soon (Stage 3 for TC39) and already available in polyfill core-js) is the new groupBy method on the array object.
This will allows you to do it directly like this :
employees.groupBy(employee => employee.company);
or even :
employees.groupBy(({company}) => company);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/groupBy

let employees = [
{name: 'Alina', company: 'Google', id : 1},
{name: 'Vika', company: 'Coca Cola', id : 2},
{name: 'Alex', company: 'Jonson & Jonson', id : 3},
{name: 'Vlad', company: 'Google', id : 4},
{name: 'Fibi', company: 'Coca Cola', id : 5},
{name: 'Joey', company: 'Google', id : 6},
]
function groupBy(arr, property) {
return arr.reduce(function (memo, x) {
if (!memo[x[property]]) { memo[x[property]] = []; }
memo[x[property]].push(x);
return memo;
}, {});
};
console.log(groupBy(employees,'company'));

The simplest way would be:
let employees = [
{name: 'Alina' company: 'Google', id : 1},
{name: 'Vika' company: 'Coca Cola', id : 2},
{name: 'Alex' company: 'Jonson & Jonson', id : 3},
{name: 'Vlad' company: 'Google', id : 4},
{name: 'Fibi' company: 'Coca Cola', id : 5},
{name: 'Joey' company: 'Google', id : 6},
]
const grouped = groupBy(employees, employee => employee.company);

Mate, it seems like no respect for potential responders, if u don't even check if ur structures are free of errors, before asking a question. Nvm :/
So, there are fixed variables:
let companies = ['Google', 'Coca Cola', 'Jonson & Jonson'];
let employees = [
{name: 'Alina', company: 'Google', id : 1},
{name: 'Vika', company: 'Coca Cola', id : 2},
{name: 'Alex', company: 'Jonson & Jonson', id : 3},
{name: 'Vlad', company: 'Google', id : 4},
{name: 'Fibi', company: 'Coca Cola', id : 5},
{name: 'Joey', company: 'Google', id : 6}]
Please notice that companies is redundant, as all the needed info is in employees.
The structure that you are looking for is probably Map. You simply do:
let map = new Map()
employees.forEach((currentValue) => {
map.has(currentValue.company)
? map.get(currentValue.company).push({name: currentValue.name, id: currentValue.id})
: map.set(currentValue.company, [{name: currentValue.name, id: currentValue.id}])
});
to get this result (field company won't be needed anymore in employee object):
{
Coca Cola: [{
id: 2,
name: "Vika"
}, {
id: 5,
name: "Fibi"
}],
Google: [{
id: 1,
name: "Alina"
}, {
id: 4,
name: "Vlad"
}, {
id: 6,
name: "Joey"
}],
Jonson & Jonson: [{
id: 3,
name: "Alex"
}]
}

Since you are going the simple route it would be slightly long.
let companies = ['Google', 'Coca Cola,' 'Jonson & Jonson',];
let employees = [
{name: 'Alina' company: 'Google', id : 1},
{name: 'Vika' company: 'Coca Cola', id : 2},
{name: 'Alex' company: 'Jonson & Jonson', id : 3},
{name: 'Vlad' company: 'Google', id : 4},
{name: 'Fibi' company: 'Coca Cola', id : 5},
{name: 'Joey' company: 'Google', id : 6},
]
//Let's create an intermediate object
let interm = {};
/*This would create an object like
{
Key:[],
Key2:[],
...
}
*/
companies.forEach((each)=>{
interm[`${each}`] = [];
})
/*filling that interm a
Object with values like
{
'Google':[
{name: 'Alina' company: 'Google', id : 1},
{name: 'Vlad' company: 'Google', id : 4},
{name: 'Joey' company: 'Google', id : 6}
],
Coca Cola:[
{name: 'Vika' company: 'Coca Cola', id : 2},
{name: 'Fibi' company: 'Coca Cola', id : 5},
],
"Jonson & Jonson":[
{name: 'Alex' company: 'Jonson & Jonson', id : 3},
]
}
*/
employee.forEach((each)=>{
if(companies.indexOf(each.company) != -1)
interm[`${each.company}`].push(each)
})
//Now our intermediate data is ready
//We need to convert to our desirable format
let finalArray = []
Object.keys(interm).forEach((each)=>{
finalArray.push({each:interm[`${each}`]})
})
console.log(finalArray)

Related

Compare two arrays of objects and filter out similar property values?

I'm calling two API endpoints: the first one will return an array of clients whose account is currently active with us, and the second will return an array of ALL clients (current and past) regardless of their current status.
I'm creating a dropdown menu that will basically add a client to the "active client" array. To create this dropdown, I need to filter out all clients from the "All clients array" that already exist in the "Active clients array".
Eg:
ALL clients
[{name: "Martha", id: 1}, {name: "John", id: 2},{name: "Jane", id: 3}, {name: "Mary", id: 4}]
Active clients
[{name: "John", customerid: 2}, {name: "Mary", customerid: 4}]
(Yes, the backend dev did give them different property names)
My new array should obviously be:
[{name: "Martha", id: 1}, {name: "Jane", id: 3}]
I can iterate through this list to populate the dropdown menu and only submit a client to the backend that doesn't already have an active account with us.
If you can consider the ids to be unique then you could do something like this:
function removeDuplicates(allClients, activeClients) {
const activeClientIds = new Set(
activeClients.map((client) => client.customerid)
);
return allClients.filter((client) => !activeClientIds.has(client.id));
}
const allClientsArr = [
{ name: "Martha", id: 1 },
{ name: "John", id: 2 },
{ name: "Jane", id: 3 },
{ name: "Mary", id: 4 },
];
const activeClientsArr = [
{ name: "John", customerid: 2 },
{ name: "Mary", customerid: 4 },
];
const result = removeDuplicates(allClientsArr, activeClientsArr);
console.log(result);
You can use a simple .filter. Also, your example result is actually missing a element.
const all = [{name: "Martha", id: 1}, {name: "John", id: 2},{name: "Jane", id: 3}, {name: "Mary", id: 4}]
const old = [{name: "John", customerid: 2}, {name: "Mary", customerid: 4}];
const oldIds = old.map(customer => customer.customerid);
console.log(all.filter(customer => !(customer.id in oldIds)))

Array of products arrange by category

I'm trying to arrange this array of products by categories. For now, I get the count of each category but I can't figure out how to make this two dimension array output.
let products = [
{name: 'Tequila', category: 'drink'},
{name: 'Beer', category: 'drink'},
{name: 'Burger', category: 'food'},
{name: 'Shawarma', category: 'food'},
{name: 'Wine', category: 'drink'},
{name: 'Gelatto', category: 'dessert'}
];
/*expected ouput
let arranged = [[
{name: 'Tequila', category: 'drink'},
{name: 'Beer', category: 'drink'},
{name: 'Wine', category: 'drink'}
], [
{name: 'Burger', category: 'food'},
{name: 'Shawarma', category: 'food'}
], [
{name: 'Gelatto', category: 'dessert'}
]];
*/
This is my code for now:
let products = [
{name: 'Tequila', category: 'drink'},
{name: 'Beer', category: 'drink'},
{name: 'Burger', category: 'food'},
{name: 'Shawarma', category: 'food'},
{name: 'Wine', category: 'drink'},
{name: 'Gelatto', category: 'dessert'}
];
let arranged = {};
products.map(x => arranged[x.category] = 1 + (arranged[x.category] || 0));
console.log(arranged);
You can group elements by reducing over the array using an object to store elements belonging to each category. To get the grouped categories, we can use Object.values.
let products = [{name: 'Tequila', category: 'drink'},
{name: 'Beer', category: 'drink'},
{name: 'Burger', category: 'food'},
{name: 'Shawarma', category: 'food'},
{name: 'Wine', category: 'drink'},
{name: 'Gelatto', category: 'dessert'}];
const res = Object.values(
products.reduce((acc,curr)=>(
(acc[curr.category] = acc[curr.category] || []).push(curr), acc
), {})
);
console.log(res);
Try this.I am using Array.prototype.reduce() to group the objects in array by category key ,then you can get the required data with Object.values()
let products = [{
name: 'Tequila',
category: 'drink'
},
{
name: 'Beer',
category: 'drink'
},
{
name: 'Burger',
category: 'food'
},
{
name: 'Shawarma',
category: 'food'
},
{
name: 'Wine',
category: 'drink'
},
{
name: 'Gelatto',
category: 'dessert'
}
];
let group = products.reduce((r, a) => {
r[a.category] = [...r[a.category] || [], a];
return r;
}, {});
console.log(Object.values(group));
I use reducer to go over the array. For builing the groups I use an index-array where I store the category. Before adding a new item I look if in this array exists the category. If so I take the index and just add to this index-th group the item. Otherwise I create a new grup-array to which I add the item.
let products = [{name: 'Tequila', category: 'drink'},
{name: 'Beer', category: 'drink'},
{name: 'Burger', category: 'food'},
{name: 'Shawarma', category: 'food'},
{name: 'Wine', category: 'drink'},
{name: 'Gelatto', category: 'dessert'}];
let categories=[];
let res = products.reduce((new_object, current_item) => {
index = categories.indexOf(current_item.category);
if (index==-1) {
categories.push(current_item.category)
new_object.push([current_item]);
} else {
new_object[index].push(current_item);
}
return new_object;
}, []);
console.log(res);

How do I search and iterate this object for an id?

I have an object where the values are arrays and they've further objects inside them like this:
let primaryStandard = {
section1: [{name: 'andy', id: 1}, {name: 'charles', id: 2},...],
section2: [{name: 'megan', id: 55}, {name: 'derek', id: 56},...],
section3: [{name: 'robert', id: 95}, {name: 'nathan', id: 96},...],
}
Basically, I want to iterate this whole object for a particular id value and then get the name and section in an object.
Example:
For id = 95 the result should be {section: section3, name: 'robert`}
What I've tried so far:
let primaryStandard = {
section1: [{name: 'andy', id: 1}, {name: 'charles', id: 2}],
section2: [{name: 'megan', id: 55}, {name: 'derek', id: 56}],
section3: [{name: 'robert', id: 95}, {name: 'nathan', id: 96}],
}
for (let key of Object.keys(primaryStandard)) {
console.log((primaryStandard[key])) // logs the values(array)
primaryStandard[key].map(student => console.log(student)) // .map() is not defined error
}
You could do this using find method on Object.keys to get section and name.
let data = {section1: [{name: 'andy', id: 1}, {name: 'charles', id: 2}],section2: [{name: 'megan', id: 55}, {name: 'derek', id: 56}],section3: [{name: 'robert', id: 95}, {name: 'nathan', id: 96}],}
let name;
let section = Object.keys(data).find(key => {
const match = data[key].find(({id}) => id == 95);
if(match) return name = match.name
})
console.log({name, section})

What is smallest way to split object into array of object based on key/value pairs in Javascript?

I've got this object:
var obj = {
family : [{name: 'will', age: 30}, {name: 'husain', age: 12}],
friends : [{name: 'cody', age: 31}, {name: 'jeff', age: 11}],
school : [{name: 'daniel', age: 20}, {name: 'carl', age: 15}]
}
convert it into this
var obj = [
{family : [{name: 'will', age: 30}, {name: 'husain', age: 12}]},
{friends : [{name: 'cody', age: 31}, {name: 'jeff', age: 11}]},
{school : [{name: 'daniel', age: 20}, {name: 'carl', age: 15}]}
];
Write now I am using for..in to build a new array and create object with key as key for new object and so on.
I'm doing this right now
var arr = [];
for (let key in obj) {
arr.push({key: obj[key]})
}
I think Object.keys is your best option:
var obj = {
family : [{name: 'will', age: 30}, {name: 'husain', age: 12}],
friends : [{name: 'cody', age: 31}, {name: 'jeff', age: 11}],
school : [{name: 'daniel', age: 20}, {name: 'carl', age: 15}]
}
var r = Object.keys(obj).map(x => ({[x]: obj[x]}) )
console.log(r)

Javascript merge array values belonging to different keys in object

I have an object like this:
data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
I want to merge the array values of the keys, and make a single array of objects like this:
[ {name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}, {name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}, {name: 'MNO', age: '19'}, {name: 'PQR', age: '24'} ]
I went through the Lodash docs to find something, but cannot come up with the right combination. Does anyone know how to do this in a concise way, with Lodash (preferably), or something else? Thanks in advance!!
Extract the arrays using _.values(), and apply concat to the arrays:
var data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
var result = Array.prototype.concat.apply([], _.values(data));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
You just need to convert the array like object to an array, then flatten it.
data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
console.log(
_.flatten(_.toArray(data))
)
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>
Without lodash, just plain old JS:
var data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
var result = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
result = result.concat(data[key]);
}
}
console.log(result);
With the new Object.values() you may do as follows in pure JS ES6;
var data = { 0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
},
newData = [].concat(...Object.values(data));
console.log(newData);
Here is another pure javascript version.
var data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
var newdata = Object.keys(data).reduce(function (a,b) {
return a.concat(data[b]);
}, []);
console.log(newdata);

Categories