I have some data that looks like :
{
_id: "5e985a07feddae7617ac44f6",
age: 24,
eyeColor: "brown",
name: "Cummings Baxter",
gender: "male",
company: "VELOS",
email: "cummingsbaxter#velos.com",
phone: "+1 (907) 482-2451",
tags: ["labore", "elit", "excepteur", "nisi", "mollit", "anim", "aliquip"],
friends: [
{
id: 0,
name: "Sheppard Jensen",
},
],
},
{
_id: "5e985a0709dfa1e6fd93c6ad",
age: 32,
eyeColor: "brown",
name: "Madelyn Dickson",
gender: "female",
company: "KENGEN",
email: "madelyndickson#kengen.com",
phone: "+1 (984) 521-2439",
tags: ["nisi", "veniam", "dolore", "officia", "ex", "non", "pariatur"],
friends: [
{
id: 0,
name: "Bruce Barton",
},
{
id: 1,
name: "Juliet Schmidt",
},
{
id: 2,
name: "Horton Haley",
},
{
id: 3,
name: "Herminia Witt",
},
],
},
{
_id: "5e985a0737e2306e9aef6ecd",
age: 26,
eyeColor: "blue",
name: "Mcguire Mercado",
gender: "male",
company: "LINGOAGE",
email: "mcguiremercado#lingoage.com",
phone: "+1 (963) 450-2194",
tags: ["cupidatat", "occaecat", "amet", "qui", "elit", "esse", "deserunt"],
friends: [
{
id: 0,
name: "Loraine Harper",
},
{
id: 1,
name: "Luann Randall",
},
{
id: 2,
name: "Obrien Rich",
},
{
id: 3,
name: "Noble Wilkerson",
},
],
},
{
_id: "5e985a07148cfba58c860ec2",
age: 26,
eyeColor: "brown",
name: "Marina Porter",
gender: "female",
company: "GORGANIC",
email: "marinaporter#gorganic.com",
phone: "+1 (867) 417-3497",
tags: [
"laborum",
"aliquip",
"sit",
"adipisicing",
"aute",
"cupidatat",
"aliquip",
],
friends: [
{
id: 0,
name: "Blair Hill",
},
{
id: 1,
name: "Ebony Jimenez",
},
],
},
{
_id: "5e985a074984f9f08ccaaa4c",
age: 255,
eyeColor: "green",
name: "Barlow Ferguson",
gender: "male",
company: "TOYLETRY",
email: "barlowferguson#toyletry.com",
phone: "+1 (837) 484-2231",
tags: ["est", "dolor", "minim", "ut", "anim", "culpa", "non"],
friends: [
{
id: 0,
name: "Delacruz Acevedo",
},
{
id: 1,
name: "Gloria Tanner",
},
{
id: 2,
name: "Cantrell Myers",
},
{
id: 3,
name: "Fisher Leonard",
},
{
id: 3,
name: "Gloria Tenner",
},
],
},
];
I want to write a function that recursively filters for desired word and returns object which contains that word.
example : function filterWith(data, "Sheppard Jensen") would return
_id: "5e985a07feddae7617ac44f6",
age: 24,
eyeColor: "brown",
name: "Cummings Baxter",
gender: "male",
company: "VELOS",
email: "cummingsbaxter#velos.com",
phone: "+1 (907) 482-2451",
tags: ["labore", "elit", "excepteur", "nisi", "mollit", "anim", "aliquip"],
friends: [
{
id: 0,
name: "Sheppard Jensen",
},
],
},
I could do this non-recursively but since resursive way could be much more efficient I want to know the way to do this. Would really apreciate any help.
here is a simple way , because JSON.stringify itself use recursively way
function filterWith(data, str) {
return data.filter(each => JSON.stringify(each).indexOf(str) > -1)
}
but you would like to do it by yourself, you can try this way
function filterWith(data, str) {
const isTarget = (_, str) => _.indexOf(str) > -1;
const $filterWith = ($data) => {
if ($data === undefined || $data === null) {
return false;
}
if (typeof $data != 'object' ) {
return isTarget(`${$data}`, `${str}`)
}
if (Array.isArray($data)) {
for (let i of $data) {
if ($filterWith($data[i])) return true
}
}
for (let i in $data) {
if (isTarget(`${data}`, `${i}`) || $filterWith($data[i])) return true
}
return false
}
return data.filter(each => $filterWith(each))
}
I would write a fairly simple recursive check that a given object contains a the string and then write a trivail filter on top of this.
const hasString = (str) => (obj) =>
Array.isArray (obj)
? obj .some (hasString (str))
: Object (obj) === obj
? hasString (str) (Object. values (obj))
: typeof obj === 'string'
? obj .includes (str)
: false
const filterWith = (xs, str) =>
xs .filter (hasString (str))
const input = [{_id: "5e985a07feddae7617ac44f6", age: 24, eyeColor: "brown", name: "Cummings Baxter", gender: "male", company: "VELOS", email: "cummingsbaxter#velos.com", phone: "+1 (907) 482-2451", tags: ["labore", "elit", "excepteur", "nisi", "mollit", "anim", "aliquip"], friends: [{id: 0, name: "Sheppard Jensen"}]}, {_id: "5e985a0709dfa1e6fd93c6ad", age: 32, eyeColor: "brown", name: "Madelyn Dickson", gender: "female", company: "KENGEN", email: "madelyndickson#kengen.com", phone: "+1 (984) 521-2439", tags: ["nisi", "veniam", "dolore", "officia", "ex", "non", "pariatur"], friends: [{id: 0, name: "Bruce Barton"}, {id: 1, name: "Juliet Schmidt"}, {id: 2, name: "Horton Haley"}, {id: 3, name: "Herminia Witt"}]}, {_id: "5e985a0737e2306e9aef6ecd", age: 26, eyeColor: "blue", name: "Mcguire Mercado", gender: "male", company: "LINGOAGE", email: "mcguiremercado#lingoage.com", phone: "+1 (963) 450-2194", tags: ["cupidatat", "occaecat", "amet", "qui", "elit", "esse", "deserunt"], friends: [{id: 0, name: "Loraine Harper"}, {id: 1, name: "Luann Randall"}, {id: 2, name: "Obrien Rich"}, {id: 3, name: "Noble Wilkerson"}]}, {_id: "5e985a07148cfba58c860ec2", age: 26, eyeColor: "brown", name: "Marina Porter", gender: "female", company: "GORGANIC", email: "marinaporter#gorganic.com", phone: "+1 (867) 417-3497", tags: ["laborum", "aliquip", "sit", "adipisicing", "aute", "cupidatat", "aliquip"], friends: [{id: 0, name: "Blair Hill"}, {id: 1, name: "Ebony Jimenez"}]}, {_id: "5e985a074984f9f08ccaaa4c", age: 255, eyeColor: "green", name: "Barlow Ferguson", gender: "male", company: "TOYLETRY", email: "barlowferguson#toyletry.com", phone: "+1 (837) 484-2231", tags: ["est", "dolor", "minim", "ut", "anim", "culpa", "non"], friends: [{id: 0, name: "Delacruz Acevedo"}, {id: 1, name: "Gloria Tanner"}, {id: 2, name: "Cantrell Myers"}, {id: 3, name: "Fisher Leonard"}, {id: 3, name: "Gloria Tenner"}]}]
console .log (filterWith (input, 'Sheppard Jensen'))
.as-console-wrapper {max-height: 100% !important; top: 0}
hasString checks if the input is an array, and if it is, simply recurs over its children until it finds a match, returning false if none match. If the input is an object, we do the same thing with its keys. If the input is a string, we see if it includes the target value. (You might prefer an equality check here.) And if it's not a string, object, or array, it returns false.
filterWith is a simple wrapper that filters an input array using hasString.
Related
This is the data I am working with below.
const data = [
{
name: "Frank Blanchard",
gender: "male",
friends: [
{
name: "Corina Irwin",
gender: "female",
sub_friends: [
{
name: "Alyssa Shelton",
eyeColor: "brown",
gender: "female",
},
{
name: "Patrice Morton",
eyeColor: "blue",
gender: "female",
},
{
name: "Hazel Berry",
eyeColor: "blue",
gender: "female",
},
{
name: "Tricia Wells",
eyeColor: "blue",
gender: "female",
},
{
name: "Mendoza Patton",
eyeColor: "blue",
gender: "male",
},
],
},
{
name: "Jayne Boyd",
gender: "female",
sub_friends: [
{
name: "Jacobs Potter",
eyeColor: "blue",
gender: "male",
},
],
},
{
name: "Justine Fox",
gender: "female",
sub_friends: [
{
name: "Madeline Harrell",
eyeColor: "brown",
gender: "female",
},
{
name: "Simpson Pratt",
eyeColor: "blue",
gender: "male",
},
{
name: "Rachel Mooney",
eyeColor: "blue",
gender: "female",
},
],
},
],
},
{
name: "Ingrid Blackwell",
gender: "female",
friends: [
{
name: "Melody Carroll",
gender: "female",
sub_friends: [
{
name: "Sonja Gillespie",
eyeColor: "blue",
gender: "female",
},
],
},
{
name: "Herring Kaufman",
gender: "male",
sub_friends: [
{
name: "Kathy Pennington",
eyeColor: "blue",
gender: "female",
},
{
name: "Marisa Mckee",
eyeColor: "blue",
gender: "female",
},
{
name: "Gillespie Dyer",
eyeColor: "brown",
gender: "male",
},
{
name: "Aida Cantrell",
eyeColor: "blue",
gender: "female",
},
{
name: "Lucy Mcconnell",
eyeColor: "brown",
gender: "female",
},
],
},
],
},
{
name: "Isabelle Moon",
gender: "female",
friends: [
{
name: "Elnora Stone",
gender: "female",
sub_friends: [
{
name: "Collins Alford",
eyeColor: "brown",
gender: "male",
},
],
},
],
},
];
I want to go through to sub_friends and return all that match gender === male. My initial test was filtering to the sub_friends, which I then returned. But I am getting an empty array.
var filtered = data.filter(({ friends }) => {
friends.filter(({ sub_friends }) => {
return sub_friends.filter((element) => element.gender === "male");
});
});
console.log("LOG: ", filtered);
I also tried using map
var filtered = data.map(({ friends }) => {
friends.map(({ sub_friends }) => {
return sub_friends.filter((element) => element.gender === "male");
});
});
console.log("LOG: ", filtered);
I get
Array(3) [ undefined, undefined, undefined ]
The output I want is an array, that I can map, to display the names in sub_friends.
You can use flatMap and filter together to achieve your goal.
flatMap is to group all specific items into a new array.
From your data, you have a list of friends and then find all sub_friends to put them under the same array. The last part is filtering all info.gender === "male" from sub_friends.
//minified your data (not important)
const data=[{name:"Frank Blanchard",gender:"male",friends:[{name:"Corina Irwin",gender:"female",sub_friends:[{name:"Alyssa Shelton",eyeColor:"brown",gender:"female"},{name:"Patrice Morton",eyeColor:"blue",gender:"female"},{name:"Hazel Berry",eyeColor:"blue",gender:"female"},{name:"Tricia Wells",eyeColor:"blue",gender:"female"},{name:"Mendoza Patton",eyeColor:"blue",gender:"male"}]},{name:"Jayne Boyd",gender:"female",sub_friends:[{name:"Jacobs Potter",eyeColor:"blue",gender:"male"}]},{name:"Justine Fox",gender:"female",sub_friends:[{name:"Madeline Harrell",eyeColor:"brown",gender:"female"},{name:"Simpson Pratt",eyeColor:"blue",gender:"male"},{name:"Rachel Mooney",eyeColor:"blue",gender:"female"}]}]},{name:"Ingrid Blackwell",gender:"female",friends:[{name:"Melody Carroll",gender:"female",sub_friends:[{name:"Sonja Gillespie",eyeColor:"blue",gender:"female"}]},{name:"Herring Kaufman",gender:"male",sub_friends:[{name:"Kathy Pennington",eyeColor:"blue",gender:"female"},{name:"Marisa Mckee",eyeColor:"blue",gender:"female"},{name:"Gillespie Dyer",eyeColor:"brown",gender:"male"},{name:"Aida Cantrell",eyeColor:"blue",gender:"female"},{name:"Lucy Mcconnell",eyeColor:"brown",gender:"female"}]}]},{name:"Isabelle Moon",gender:"female",friends:[{name:"Elnora Stone",gender:"female",sub_friends:[{name:"Collins Alford",eyeColor:"brown",gender:"male"}]}]}];
//the main logic
const results = data.flatMap(info => info.friends).flatMap(info => info.sub_friends).filter(info => info.gender === "male")
console.log(results)
The reduce function can help here (see the result image below).
The output can be further adjusted to store all the values in single array:
let output = data.reduce(function(acc,curr) {
let male = curr.friends.reduce(function(acc1,curr1) {
acc1.push(curr1.sub_friends);
return acc1;
}, []);
acc.push(male);
return acc;
},[]);
let male = output.reduce(function(acc,curr) {
let male1 = curr.reduce(function(acc1,curr1) {
acc1.push(curr1.filter((x) => x.gender === "male"));
return acc1;
},[]);
acc.push(male1);
return acc;
},[])
console.log(male);
A simpler and Specified method would be this approach which you can use forEach method and make a nested loop over the object of array and push sub_feriend name into arr and after that filter the array to get just the names
let arr = [];
data.forEach(({friends}) =>{
friends.forEach(({sub_friends}) => {
arr.push(sub_friends.find(x => x.gender === "male"))
})
})
let names = arr.filter(x => x !== undefined).map(x => x.name)
console.log(names)
There is a thatre establishment that has a number of theatre groups. Each groups is either international or not. For some reason it is necessary that each international group has at least one female actor , aka. actress. If there exists even one international group without any female actor, function checkGenderEquality must return false.
Theatre: [
{
groupNmae: 'Medea',
id: 1001,
international: false,
actors: [
{
firstName: 'Vilfrid',
birthDate: '1981-01-01',
gender: 'Male',
},
{
firstName: 'Nils',
birthDate: '1973-10-11',
gender: 'Male'
},
{
firstName: 'Valentina',
birthDate: '2001-05-09',
gender: 'Female'
}
]
}
,
{
groupNmae: 'Hamlet',
id: 2001,
international: true,
actors: [
{
firstName: 'Robin',
birthDate: '1999-07-20',
gender: 'Male'
},
{
firstName: 'Johannes',
birthDate: '1998-12-13',
gender: 'Male'
},
{
firstName: 'Ludwig',
birthDate: '1965-03-22',
gender: 'Male'
}
]
},
{
groupNmae: 'King Lear',
id: 3001,
international: true,
actors: [
{
firstName: 'Kristina',
birthDate: '1977-04-19',
gender: 'Female'
},
{
firstName: 'Pernilla',
birthDate: '1974-02-03',
gender: 'Female'
},
{
firstName: 'Bruno',
birthDate: '1970-02-23',
gender: 'Male'
}
]
},
{
groupNmae: 'Medea',
id: 4001,
international: false,
actors: [
{
firstName: 'Alfons',
birthDate: '1986-11-01',
gender: 'Male',
},
{
firstName: 'Ulrik',
birthDate: '1979-11-01',
gender: 'Male'
},
{
firstName: 'Oskar',
birthDate: '2000-10-10',
gender: 'Male'
}
]
}
]
public checkGenderEquality(theatreGroup: any[]) {
let equality = theatreGroup.every(({ t }) =>
(
(t.international != false) || (t.some((a) => a.gender == 'Female')))
);
return equality;
}
Currently checkGenderEquality returns always true. How can I modify to get the correct result (which in this case is false; becuse Hamlet is an international group but has no female actor)?
If the group.international === false, you don't need to check the actors. if the group.international === true, you need to check actors.
Updated: replace filter with every and some
const theatre = [
{
groupNmae: "Medea",
id: 1001,
international: true,
actors: [
{
firstName: "Valentina",
birthDate: "2001-05-09",
gender: "Female",
},
],
},
{
groupNmae: "Hamlet",
id: 2001,
international: true,
actors: [
{
firstName: "Ludwig",
birthDate: "1965-03-22",
gender: "Male",
},
],
},
];
const isEquality = theatre.every(
item =>
(item.international === true &&
item.actors.some(actor => actor.gender === "Female")) ||
item.international === false
);
console.log(isEquality);
So, let's suppose I have this:
var officers = [
{ id: 20, name: 'Captain', lastName: 'Piett' },
{ id: 24, name: 'General', lastName: 'Veers' },
{ id: 56, name: 'Admiral', lastName: 'Ozzel' },
{ id: 88, name: 'Commander', lastName: 'Jerjerrod' }
];
If I do this:
var officersIds = officers.map(x => [x.name, x.lastName]);
the result of officersIds is gonna be this:
[ "Captain", "Piett" ], [ "General", "Veers" ], [ "Admiral", "Ozzel" ], [ "Commander", "Jerjerrod" ]
right?
So, what I need to do is to put an object on each map iteration so the output is now this, for example:
[["x", "y"], [ "Captain", "Piett" ]],
[["x", "y"], [ "General", "Veers" ]],
[["x", "y"], [ "Admiral", "Ozzel" ]],
[["x", "y"], [ "Commander", "Jerjerrod" ]]
Why do I need this? Better don't ask ;) But it's a complex problem and if you help me solve this simple one I could transfer your solution to my complex problem.
IMPORTANT: Is there a way to do this in one line?
If you simply want to add ['x', 'y'] to the start of the array, you can use the spread operator to make it a one-liner:
var officersIds = [['x', 'y'], ...officers.map(x => [x.name, x.lastName])];
See proof-of-concept below:
var officers = [
{ id: 20, name: 'Captain', lastName: 'Piett' },
{ id: 24, name: 'General', lastName: 'Veers' },
{ id: 56, name: 'Admiral', lastName: 'Ozzel' },
{ id: 88, name: 'Commander', lastName: 'Jerjerrod' }
];
var officersIds = [['x', 'y'], ...officers.map(x => [x.name, x.lastName])];
console.log(officersIds);
However, if you want to add ['x', 'y'] to each item in the array, then you should do this instead:
var officersIds = officers.map(x => [['x', 'y'], [x.name, x.lastName]]);
var officers = [
{ id: 20, name: 'Captain', lastName: 'Piett' },
{ id: 24, name: 'General', lastName: 'Veers' },
{ id: 56, name: 'Admiral', lastName: 'Ozzel' },
{ id: 88, name: 'Commander', lastName: 'Jerjerrod' }
];
var officersIds = officers.map(x => [['x', 'y'], [x.name, x.lastName]]);
console.log(officersIds);
var officers = [
{ id: 20, name: 'Captain', lastName: 'Piett' },
{ id: 24, name: 'General', lastName: 'Veers' },
{ id: 56, name: 'Admiral', lastName: 'Ozzel' },
{ id: 88, name: 'Commander', lastName: 'Jerjerrod' },
];
officers.unshift({ name: x, lastName: y });
var officersIds = officers.map(x => [x.name, x.lastName]);
Or
var officers = [
{ id: 20, name: 'Captain', lastName: 'Piett' },
{ id: 24, name: 'General', lastName: 'Veers' },
{ id: 56, name: 'Admiral', lastName: 'Ozzel' },
{ id: 88, name: 'Commander', lastName: 'Jerjerrod' },
];
var officersIds = officers.map(x => [x.name, x.lastName]);
officersIds.unshift(["x", "y" ]);
You could just add the wanted parts to the mapping function.
var officers = [{ id: 20, name: 'Captain', lastName: 'Piett' }, { id: 24, name: 'General', lastName: 'Veers' }, { id: 56, name: 'Admiral', lastName: 'Ozzel' }, { id: 88, name: 'Commander', lastName: 'Jerjerrod' }],
officersIds = officers.map(x => [["x", "y"], [x.name, x.lastName]]);
console.log(officersIds);
Use Map over officers.
var officers = [
{ id: 20, name: 'Captain', lastName: 'Piett' },
{ id: 24, name: 'General', lastName: 'Veers' },
{ id: 56, name: 'Admiral', lastName: 'Ozzel' },
{ id: 88, name: 'Commander', lastName: 'Jerjerrod' }
];
var officersIds = officers.map(x => [["x", "y"], [x.name, x.lastName]]);
console.log(officersIds);
There are two object array, some of them have the same key, I'd like to merge the same key in the first array. I have pasted my code.I used nested loop, but the performance was bad O(n²). Maybe I need another method to enhance performance.(I can't use ES6 for some reason, so I'll appreciate if it is the ES5 method.)
var people = [
{
id: "001",
name: "David",
age: 29
},
{
id: "002",
name: "Lucia",
age: 41
},
{
id: "003",
name: "Steve",
age: 18
}
];
var address = [
{
id: "001",
city: "Barcelona"
},
{
id: "002",
city: "Paris"
},
{
},
{
id: "003",
city: "Tokyo"
},
{
id: "004",
city: "Barcelona"
}
];
My code
people.forEach(function(item) {
var id = item.id;
address.forEach(function(location) {
if (location.id == id) {
item.address = location.address
}
});
});
Result
var people = [
{
id: "001",
name: "David",
age: 29,
city: "Barcelona"
},
{
id: "002",
name: "Lucia",
age: 41,
city: "Paris"
},
{
id: "003",
name: "Steve",
age: 18,
city: "Tokyo"
}
];
The new people array is I preferred.
You could take a Map with all addresses and then map new object with extended properties of the map.
This approach takes all properties of address objects.
var people = [{ id: "001", name: "David", age: 29 }, { id: "002", name: "Lucia", age: 41 }, { id: "003", name: "Steve", age: 18 }],
address = [{ id: "001", city: "Barcelona" }, { id: "002", city: "Paris" }, {}, { id: "003", city: "Tokyo" }, { id: "004", city: "Barcelona" }],
map = new Map(address.map(o => [o.id, o])),
result = people.map(o => Object.assign({}, o, map.get(o.id)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Make a Map with cities by id, and use it when iterating over the people array to find out the city:
let cities = new Map(address.map(a => [a.id, a.city]));
let people2 = people.map(p => ( {...p, city: cities.get(p.id)} ));
You could use Array#map to iterate over people, and Array#find to find the corresponding address from id within iterations:
const people = [{id: "001",name: "David",age: 29 },{ id: "002", name: "Lucia", age: 41
},{ id: "003", name: "Steve", age: 18 }],
address = [{ id: "001", city: "Barcelona" },{ id: "002", city: "Paris" },{ },{ id: "003", city: "Tokyo" },{ id: "004", city: "Barcelona" }];
console.log(
people.map(p => ({
...p,
...address.find(a => (p.id === a.id))
}))
);
However, that's supposing that the properties' name of address's items are not the same as people's ones.
The code below is not tested but it should work
// create an object to store them
const mergedItems = {};
// merge the 2 arrays so you only map them once (just for shorter code)
people.concat(address).map(entity => {
// add each entity on the object and id as a key
mergedItems[entity.id] = {
// if the key exist, it will merge it with the new entity
...mergedItems[entity.id],
...entity,
}
)
// this is your merged items
// Object.values will convert it from object to array
const finalItems = Object.values(mergedItems);
I used map instead of for loop because it is faster: https://codeburst.io/javascript-map-vs-foreach-f38111822c0f
I have used Object.assign method to add values from address
var people = [{ id: "001", name: "David", age: 29 }, { id: "002", name: "Lucia", age: 41 }, { id: "003", name: "Steve", age: 18 }],
address = [{ id: "001", city: "Barcelona" }, { id: "002", city: "Paris" }, {}, { id: "003", city: "Tokyo" }, { id: "004", city: "Barcelona" }];
people.forEach(function(item,pos){
Object.assign(item,{},address[address.findIndex(o=>o.id == item.id)]);
});
console.log(people);
How can I group data in Angular 2 with TypeScript. I am aware that this is done using "group by" filter in Angular 1.X, but not getting how to group data in Angular 2. I have this array:
import {Employee} from './employee';
export var employees: Employee[];
employees = [
{ id: 1, firstName: "John", lastName: "Sonmez", department: 1, age: 24, address: "24/7, Working hours apartment, Cal. US", contactNumber: "+968546215789" },
{ id: 2, firstName: "Mark", lastName: "Seaman", department: 2, age: 25, address: "32-C, Happy apartments, Block-9C, Cal. US", contactNumber: "+968754216984" },
{ id: 3, firstName: "Jamie", lastName: "King", department: 3, age: 32, address: "54/II, Glorydale apartment, Cal. US", contactNumber: "+967421896326" },
{ id: 5, firstName: "Jacob", lastName: "Ridley", department: 5, age: 24, address: "24/7, Working hours apartment, Cal. US", contactNumber: "+968546215789" },
{ id: 6, firstName: "Peter", lastName: "Parker", department: 3, age: 25, address: "32-C, Happy apartments, Block-9C, Cal. US", contactNumber: "+968754216984" },
{ id: 7, firstName: "Martin", lastName: "Luther", department: 4, age: 32, address: "54/II, Glorydale apartment, Cal. US", contactNumber: "+967421896326" },
{ id: 8, firstName: "Raghav", lastName: "Kumar", department: 1, age: 34, address: "51/C Shivalik, Cal. US", contactNumber: "+967842569842" },
{ id: 9, firstName: "Narayan", lastName: "Sonmez", department: 3, age: 24, address: "24/7, Working hours apartment, Cal. US", contactNumber: "+968546215789" },
{ id: 10, firstName: "Russell", lastName: "Andre", department: 2, age: 25, address: "32-C, Happy apartments, Block-9C, Cal. US", contactNumber: "+968754216984" },
{ id: 11, firstName: "Ramona", lastName: "King", department: 4, age: 32, address: "54/II, Glorydale apartment, Cal. US", contactNumber: "+967421896326" },
{ id: 12, firstName: "Andre", lastName: "Russell", department: 1, age: 34, address: "51/C Shivalik, Cal. US", contactNumber: "+967842569842" },
{ id: 13, firstName: "Nathan", lastName: "Leon", department: 1, age: 24, address: "24/7, Working hours apartment, Cal. US", contactNumber: "+968546215789" },
{ id: 14, firstName: "Brett", lastName: "Lee", department: 5, age: 25, address: "32-C, Happy apartments, Block-9C, Cal. US", contactNumber: "+968754216984" },
{ id: 15, firstName: "Tim", lastName: "Cook", department: 2, age: 32, address: "54/II, Glorydale apartment, Cal. US", contactNumber: "+967421896326" },
{ id: 16, firstName: "Steve", lastName: "Jobs", department: 5, age: 34, address: "51/C Shivalik, Cal. US", contactNumber: "+967842569842" }
];
and I am looking to count the employees by department, like
Department 1 has 4 employees
and so on.
Joining the department id with actual department (so that I can get the department name) is another story I need to figure out.
I would create a custom pipe to do that as described below:
#Pipe({name: 'groupBy'})
export class GroupByPipe implements PipeTransform {
transform(value: Array<any>, field: string): Array<any> {
const groupedObj = value.reduce((prev, cur)=> {
(prev[cur[field]] = prev[cur[field]] || []).push(cur);
return prev;
}, {});
return Object.keys(groupedObj).map(key => ({ key, value: groupedObj[key] }));
}
}
And then on your template you can write:
<div *ngFor="let item of employees | groupBy: 'department'">
Department {{ item.key }} has {{ item.value.length }} employees
</div>
See also corresponding plunker https://plnkr.co/edit/49fWY1rMbSZtNQ3H
You can use ngx-pipes https://github.com/danrevah/ngx-pipes#groupby
this.arrayObject = [
{id: 1, elm: 'foo', value: 0},
{id: 2, elm: 'bar', value: 1},
{id: 3, elm: 'foo', value: 2},
{id: 4, elm: 'foo', value: 2}
];
this.arrayNestedObject = [
{id: 1, prop: { deep: 'foo' }},
{id: 2, prop: { deep: 'bar' }},
{id: 3, prop: { deep: 'foo' }},
{id: 4, prop: { deep: 'bar' }}
];
<p>{{ arrayObject | groupBy: 'elm' }}</p>
<!-- Output: "{foo: [{id: 1, elm: 'foo', value: 0}, {id: 3, elm: 'foo', value: 2}, {id: 4, elm: 'foo', value: 2}], bar: [{id: 2, elm: 'bar', value: 1}]}" -->
var dept = employees.map((m) => m.department).filter((f, i, ar) => ar.indexOf(f) === i);
console.log(dept);
var group = employees.reduce((accumulator, item, i, arr) => {
if (dept.length) {
var pop = dept.shift();
var list = arr.filter((f) => f.department == pop);
accumulator.push(...list);
}
return accumulator;
}, []);
console.log(group);
If you need to access nested properties or need to compare objects you can do
#Pipe({ name: 'groupByProperty' })
export class GroupByPropertyPipe implements PipeTransform {
transform(value: Array<any>, property: string): Array<any> {
if (!value) {
return null;
}
const group = value.reduce((previous, current) => {
const parts = property.split('.');
let currentValue: any;
parts.forEach(part => {
currentValue = currentValue ? currentValue[part] : current[part];
});
// Stringify objects for comparison
currentValue = typeof currentValue === 'object' ? JSON.stringify(currentValue) : currentValue;
if (!previous[currentValue]) {
previous[currentValue] = [current];
} else {
previous[currentValue].push(current);
}
return previous;
}, {});
return Object.keys(group).map(key => ({ key, value: group[key] }));
}
}