I have an array of objects like this one:
[
{
name: 'John',
email: 'user#mail.com',
city: 'London',
type: 'CLIENT'
},
{
name: 'Steve',
email: 'stave#mail.com',
city: 'Rome',
type: 'USER'
},
{
name: 'Mark',
email: 'mark#mail.com',
city: 'Paris',
type: 'ADMIN'
}
]
I need to transform it into something like this:
{
CLIENT: {
name: 'John',
email: 'user#mail.com',
city: 'London'
},
USER: {
name: 'Steve',
email: 'stave#mail.com',
city: 'Rome',
},
ADMIN: {
name: 'Mark',
email: 'mark#mail.com',
city: 'Paris',
type: 'ADMIN'
}
}
What's the best approach?
Thank you
Use Array#reduce with a simple object destructuring to get your desired result:
const data = [{
name: 'John',
email: 'user#mail.com',
city: 'London',
type: 'CLIENT'
},
{
name: 'Steve',
email: 'stave#mail.com',
city: 'Rome',
type: 'USER'
},
{
name: 'Mark',
email: 'mark#mail.com',
city: 'Paris',
type: 'ADMIN'
}
];
const result = data.reduce((acc, { type, ...obj }) => {
acc[type] = obj;
return acc;
}, {})
console.log(result);
With upcoming object rest properties in ES2018/ES9 or with BABEL, you could take the type property and use the rest properties for a new object for assignment.
var array = [{ name: 'John', email: 'user#mail.com', city: 'London', type: 'CLIENT' }, { name: 'Steve', email: 'stave#mail.com', city: 'Rome', type: 'USER' }, { name: 'Mark', email: 'mark#mail.com', city: 'Paris', type: 'ADMIN' }],
object = Object.assign(...array.map(({ type, ...o }) => ({ [type]: o })));
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could also use reduce() and Object.assign() to get the required result.
DEMO
var arr = [{ name: 'John', email: 'user#mail.com', city: 'London', type: 'CLIENT' }, { name: 'Steve', email: 'stave#mail.com', city: 'Rome', type: 'USER' }, { name: 'Mark', email: 'mark#mail.com', city: 'Paris', type: 'ADMIN' }];
console.log(arr.reduce((r,{type,...rest})=>Object.assign(r,{[type]:rest}),{}));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I'm trying to group the objects for the users that have the same location and type value shown in the example below. What would be the best way to approach this?
const diabetics = [
{
type: 'type 1',
location: 'Boston'
email: 'person1#gmail.com'
},
{
type: 'type 2',
location: 'New York'
email: 'person2#gmail.com'
},
{
type: 'type 1',
location: 'Boston'
email: 'person3#gmail.com'
},
{
type: 'type 1',
location: 'Maine'
email: 'person4#gmail.com'
},
]
// expected output
const diabetics = [
{
type: 'type 1',
location: 'Boston'
email: [
'person1#gmail.com',
'person3#gmail.com'
]
},
{
type: 'type 2',
location: 'New York'
email: 'person2#gmail.com'
},
{
type: 'type 1',
location: 'Maine'
email: 'person4#gmail.com'
},
]
You could also get the result using Array.reduce(), creating groups using a key composed of type and location.
Once we have a map keyed on type and location we can use Array.values() to return the desired result:
const diabetics = [ { type: 'type 1', location: 'Boston', email: 'person1#gmail.com' }, { type: 'type 2', location: 'New York', email: 'person2#gmail.com' }, { type: 'type 1', location: 'Boston', email: 'person3#gmail.com' }, { type: 'type 1', location: 'Maine', email: 'person4#gmail.com' }, ]
const result = Object.values(diabetics.reduce ((acc, { type, location, email }) => {
// Create a grouping key, in this case using type and location...
const key = [type, location].join("-");
acc[key] ||= { type, location, email: [] };
acc[key].email.push(email);
return acc;
}, {}))
console.log('Result:', result);
I have an array of object like that :
[{ name: 'Peter', age: '22', hobby: 'soccer', city: 'london' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Paris' },
{ name: 'Peter', age: '22', hobby: 'soccer', city: 'Paris' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Madrid' },
{ name: 'Rick', age: '28', hobby: 'tennis', city: 'Berlin' }],
And i would like group by the city, like below:
[{name: 'Peter', age: '22', hobby: 'soccer', cities: ['london', 'Paris']},
{name: 'Mario', age: '30', hobby: 'bike',cities: ['Paris', 'Madrid']},
{name: 'Rick', age: '28', hobby: 'tennis', cities: ['Berlin']}]
I try with this function by, I don't have the good array
let arrayPeople = [{ name: 'Peter', age: '22', hobby: 'soccer', city: 'london' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Paris' },
{ name: 'Peter', age: '22', hobby: 'soccer', city: 'Paris' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Madrid' },
{ name: 'Rick', age: '28', hobby: 'tennis', city: 'Berlin' }],
let groups = {};
for (let i = 0; i < arrayPeople.length; i++) {
let groupName = arrayPeople[i].city;
if (!groups[groupName]) {
groups[groupName] = [];
}
groups[groupName].push(arrayPeople[i].city);
}
let arrayGroupBy= [];
for (let groupName in groups) {
arrayGroupBy.push({ ...arrayPeople, cities: groups[groupName] });
}
How I can make my group by ?
Thank for your help.
You can use Array.reduce to process your input array, using the name, age and hobby as a key to create a grouping object, and adding the city for each key to an array in that object. You can then use Object.values to grab just the values from the grouping object into an array:
let arrayPeople = [{ name: 'Peter', age: '22', hobby: 'soccer', city: 'london' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Paris' },
{ name: 'Peter', age: '22', hobby: 'soccer', city: 'Paris' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Madrid' },
{ name: 'Rick', age: '28', hobby: 'tennis', city: 'Berlin' }];
let arrayGroupBy = Object.values(arrayPeople.reduce((c, { city, ...rest }) => {
let key = Object.values(rest).join('#');
c[key] = c[key] || { ...rest, city : [] };
c[key].city.push(city);
return c;
}, {}));
console.log(arrayGroupBy);
Note the above code is dependent on the properties in the objects being in the same order in each object (in the sample data, name, age, hobby). If this might not be the case, you will need to create the key using the named properties instead, for example:
let arrayPeople = [{ name: 'Peter', age: '22', hobby: 'soccer', city: 'london' },
{ age: '30', hobby: 'bike', name: 'Mario', city: 'Paris' },
{ name: 'Peter', hobby: 'soccer', city: 'Paris', age: '22' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Madrid' },
{ name: 'Rick', age: '28', hobby: 'tennis', city: 'Berlin' }];
let arrayGroupBy = Object.values(arrayPeople.reduce((c, { name, age, hobby, city}) => {
let key = `${name}#${age}#${hobby}`;
c[key] = c[key] || { name, age, hobby, city : [] };
c[key].city.push(city);
return c;
}, {}));
console.log(arrayGroupBy);
Note also that all the above code is dependent on choosing a delimiter (I've used #) that will not occur in the name or hobby values. If there is no suitable delimiter character, then it is safer to use something like JSON.stringify to produce the key value e.g. for the second code block you would use:
let key = JSON.stringify([name, age, hobby]);
Your approach is pretty near to the correct solution. You are grouping persons by city. You have to turn around and group cities by person
let arrayPeople = [{ name: 'Peter', age: '22', hobby: 'soccer', city: 'london' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Paris' },
{ name: 'Peter', age: '22', hobby: 'soccer', city: 'Paris' },
{ name: 'Mario', age: '30', hobby: 'bike', city: 'Madrid' },
{ name: 'Rick', age: '28', hobby: 'tennis', city: 'Berlin' }];
let groups = {};
for (let i = 0; i < arrayPeople.length; i++) {
let groupName = arrayPeople[i].name;
if (!groups[groupName]) {
groups[groupName] = {name: arrayPeople[i].name, age: arrayPeople[i].age, hobby: arrayPeople[i].hobby, cities: []};
}
groups[groupName].cities.push(arrayPeople[i].city);
}
console.log(Object.values(groups));
This is TypeScript so I'd probably come up with the type corresponding to the final array elements: that is, remove the city property and add a cities property:
type PersonCities = Omit<typeof arrayPeople[number], "city"> & { cities: string[] };
Then you want to put all your objects into a dictionary keyed by whatever you want the grouping condition to be (converted into a string):
const peopleCities: Record<string, PersonCities> = {};
for (let p of arrayPeople) {
const { city, ...person } = p;
const groupByKey = JSON.stringify([person.name, person.hobby, person.age]);
if (!(groupByKey in peopleCities)) {
peopleCities[groupByKey] = { ...person, cities: [] };
}
peopleCities[groupByKey].cities.push(city);
}
const arrayPeopleCities = Object.values(peopleCities);
Here we're making the grouping key a JSON string of the name, hobby, and age properties in an array. And some object rest/spread syntax to copy people properties around without too much redundancy.
Playground link to code
I tried to solve the problem on my own but I did not manage to. So I decided to ask for help.
I've got an array of JSON objects like this:
const objArr = [
{
name: 'Andrew',
city: 'London'
},
{
name: 'Edouard',
city: 'Paris'
},
{
name: 'Nathalie',
city: 'London'
},
{
name: 'Patrick',
city: 'London'
},
{
name: 'Mathieu',
city: 'Paris'
}
];
I want to gather objects with same key value - in that case the city key - in a new array to obtain this:
const newObjArr = [
[{
name: 'Andrew',
city: 'London'
},
{
name: 'Nathalie',
city: 'London'
},
{
name: 'Patrick',
city: 'London'
}],
[{
name: 'Edouard',
city: 'Paris'
},
{
name: 'Mathieu',
city: 'Paris'
}]
];
This is a job for .reduce().
const objArr = [
{name: 'Andrew', city: 'London'},
{name: 'Edouard', city: 'Paris'},
{name: 'Nathalie', city: 'London'},
{name: 'Patrick', city: 'London'},
{name: 'Mathieu', city: 'Paris'}
];
// Object of arrays
const result = objArr.reduce((acc, obj) => {
return {...acc, [obj.city]: [...acc[obj.city] || [], obj]}
}, {})
// Array of arrays
const result2 = Object.values(result);
console.log(result2)
Use lodash group by and then add to new array
var objArr = [ { name: 'Andrew', city: 'London' }, { name: 'Edouard', city: 'Paris' }, { name: 'Nathalie', city: 'London' }, { name: 'Patrick', city: 'London' }, { name: 'Mathieu', city: 'Paris' } ]
var grouped = _.mapValues(_.groupBy(objArr, 'city'),
clist => clist.map(city => _.omit(city, 'city')));
var result=[]
for (const [key, value] of Object.entries(grouped)) {
var array=[]
value.forEach(x=>{
array.push({ name: x.name, city:key })
})
result.push(array);
}
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You can use reduce to group by a field using that field as the key and then use Object.values if you really just want the values:
const objArr = [ { name: 'Andrew', city: 'London' }, { name: 'Edouard', city: 'Paris' }, { name: 'Nathalie', city: 'London' }, { name: 'Patrick', city: 'London' }, { name: 'Mathieu', city: 'Paris' } ];
var groupBy = function(array, k) {
return array.reduce(function(acc, cur) {
(acc[cur[k]] = acc[cur[k]] || []).push(cur);
return acc;
}, {});
};
console.log(Object.values(groupBy(objArr, 'city')));
I am trying to add a new object to existing object.
In my mobx Store I have an existing object which contains one user:
#observable user = {
id: 101,
email: 'kevin#dev.com',
personalInfo: {
name: 'kevin',
address: {
city: 'Costa Mesa',
state: 'CA'
}
}
}
I want to add another user to existing object:
id: 102,
email: 'john#dev.com',
personalInfo: {
name: 'john',
address: {
city: 'New York',
state: 'NY'
}
}
I want my final code to look like this:
#observable user = {
id: 101,
email: 'kevin#dev.com',
personalInfo: {
name: 'kevin',
address: {
city: 'Costa Mesa',
state: 'CA'
}
},
id: 102,
email: 'john#dev.com',
personalInfo: {
name: 'john',
address: {
city: 'New York',
state: 'NY'
}
}
}
What would be the correct format to add another object to the existing object?
Would this work?
updateObjectState (){
const user2 = {
id: 102,
email: 'john#dev.com',
personalInfo: {
name: 'john',
address: {
city: 'New York',
state: 'NY'
}
}
}
store.pressedDate = [...store.pressedDate, user2]
}
Thanks in advance!
Your desired result can't be achieved, as id is repeated so it will overwrite last id, wrap each user in object or use array
using id as key and placing values, when you want to add new user just create a new key value pair on user
#observable user = {
'101':{
id: 101,
email: 'kevin#dev.com',
personalInfo: {
name: 'kevin',
address: {
city: 'Costa Mesa',
state: 'CA'
}
}
}
}
Or having user as an array, to add new user just push the value in user
#observable user = [{
id: 101,
email: 'kevin#dev.com',
personalInfo: {
name: 'kevin',
address: {
city: 'Costa Mesa',
state: 'CA'
}
}
}]
P.S - I am not sure how you're using data, but i will go with the object way,
I want to filter this data array into state and city array. How can I achieve this using lodash or any other better way rather than for loop and maintaining extra arrays.
data: [
{ id: 1, name: Mike, city: philps, state: New York},
{ id: 2, name: Steve, city: Square, state: Chicago},
{ id: 3, name: Jhon, city: market, state: New York},
{ id: 4, name: philps, city: booket, state: Texas},
{ id: 5, name: smith, city: brookfield, state: Florida},
{ id: 6, name: Broom, city: old street, state: Florida},
]
which user click state, list of state appears.
{state: New York, count: 2},
{state: Texas, count: 1},
{state: Florida, count: 2},
{state: Chicago, count: 1},
When user click particular state, list of cities of that state appears. For ex. when user clicks New York state,
{id:1, name: Mike, city: philps}
{id:3, name: Jhon, city: market}
You can do this using native javascript by applying filter method which accepts as parameter a callback provided function.
let data = [ { id: 1, name: 'Mike', city: 'philps', state:'New York'}, { id: 2, name: 'Steve', city: 'Square', state: 'Chicago'}, { id: 3, name: 'Jhon', city: 'market', state: 'New York'}, { id: 4, name: 'philps', city: 'booket', state: 'Texas'}, { id: 5, name: 'smith', city: 'brookfield', state: 'Florida'}, { id: 6, name: 'Broom', city: 'old street', state: 'Florida'}, ]
data = data.filter(function(item){
return item.state == 'New York';
}).map(function({id, name, city}){
return {id, name, city};
});
console.log(data);
Another approach is to use arrow functions.
let data = [ { id: 1, name: 'Mike', city: 'philps', state:'New York'}, { id: 2, name: 'Steve', city: 'Square', state: 'Chicago'}, { id: 3, name: 'Jhon', city: 'market', state: 'New York'}, { id: 4, name: 'philps', city: 'booket', state: 'Texas'}, { id: 5, name: 'smith', city: 'brookfield', state: 'Florida'}, { id: 6, name: 'Broom', city: 'old street', state: 'Florida'}, ]
data = data.filter((item) => item.state == 'New York').map(({id, name, city}) => ({id, name, city}));
console.log(data);
With lodash, you could use _.filter with an object as _.matches iteratee shorthand for filtering the object with a given key/value pair and
use _.countBy with _.map for getting a count of states.
var data = [{ id: 1, name: 'Mike', city: 'philps', state: 'New York' }, { id: 2, name: 'Steve', city: 'Square', state: 'Chicago' }, { id: 3, name: 'Jhon', city: 'market', state: 'New York' }, { id: 4, name: 'philps', city: 'booket', state: 'Texas' }, { id: 5, name: 'smith', city: 'brookfield', state: 'Florida' }, { id: 6, name: 'Broom', city: 'old street', state: 'Florida' }];
console.log(_.filter(data, { state: 'New York' }));
console.log(_
.chain(data)
.countBy('state')
.map((count, state) => ({ state, count }))
.value()
);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Simply Follow filter function
For Example
return data.filter(data => data.state == "New York" && count === 2);
This is fairly simple using Array.prototype.filter, Array.prototype.map, Array.prototype.reduce and destructuring:
//filter by particular state
const state = /*the given state*/;
const filtered = data
.filter(e => e.state == state)//filter to only keep elements from the same state
.map(e => {
const {id, name, city} = e;
return {id, name, city};
});//only keep the desired data ie id, name and city
//get states array
const states = data
.reduce((acc, elem) => {
const state_names = acc.map(e => e.state);//get all registered names
if(state_names.includes(elem.state)){//if it is already there
const index = acc.find(e => e.state==elem.state);
acc[index] = {state: acc[index].state, count: acc[index].count+1};//increment it's count
return acc;
}else//otherwise
return [...acc, {state: elem.state, count: 1}];//create it
}, []);
cf this jsfiddle to see it in action.