How to count the properties of an array of objects in JavaScript - javascript

var employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }
];
For example on this one I would like to return
{
'doctor':2,
'receptionist':2
}
This is what I have tried:
const convert = (employees) => {
const res = {};
employees.forEach((employee) => {
const key = `${employee.title}${employee["doctor-receptionist"]}`;
if (!res[key]) {
res[key] = {...employee, count: 0 };
};
res[key].count += 1;
});
return Object.values(res);
};
console.log(convert(employees));
It returns the name of the employees, which I did not want.
I also thought about creating arrays for each kind of job title and filtering each employee from the employee array, and pushing them to their respective arrays. But I feel like there must be an easier way.

Array#reduce is the way to go:
const employees = [ { name: "Josh", title: "receptionist" }, { name: "Naila", title: "receptionist" }, { name: "Tom", title: "doctor" }, { name: "Becky", title: "doctor" } ],
summary = employees
.reduce((acc,{title}) => ({...acc,[title]:(acc[title] || 0) + 1}),{});
console.log( summary );

Just using reduce() can do it
var employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }
];
let result = employees.reduce((a,c) =>{
a[c.title] = a[c.title] ? a[c.title] + 1 : 1
return a
},{})
console.log(result)

The reduce iterator was built for this kind of thing.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
I also employ Object.values() since the way I am using reduce is to create an object to easily keep track of the data along the way. The object.values helps distill that into an array when done.
const employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }];
const reduced = Object.values(employees.reduce((b,a) => {
if (!b[a.title]) b[a.title] = {title: a.title, count: 1}
else b[a.title].count++;
return b
},{}))
console.log(reduced);

you can try this on your code
const employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }
]
const sumReceptionist = employees.filter((item)=>{
return item.title === 'receptionist'
}).length
const sumDoctor = employees.filter((item)=>{
return item.title === 'doctor'
}).length
let total =
{
receptionist: sumReceptionist,
doctor: sumDoctor
}
console.log(total)

I think this is what you're trying to do. You want the total of the positions from the employee list?
const Employees = [{
name: "Josh",
title: "receptionist"
},
{
name: "Naila",
title: "receptionist"
},
{
name: "Tom",
title: "doctor"
},
{
name: "Becky",
title: "doctor"
},
{
name: "Chad",
title: "doctor"
},
{
name: "Cindy",
title: "nurse"
}
];
// A forEach won't return an object or array, so we create one to modify within it
const PositionTotals = {};
Employees.forEach(employee => {
// Check if property exists. If not, create it and add one to it before continuing loop
if (!PositionTotals.hasOwnProperty(employee.title))
return PositionTotals[employee.title] = 1;
PositionTotals[employee.title]++;
})
console.log(PositionTotals);
$('#PositionTotals').html(JSON.stringify(PositionTotals, null, '\t'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<pre id="PositionTotals"></pre>

Related

get keys from the nested array of objects

I am looking for a function that can mutate my data i.e array of object with a nested object. It will include keys that have object/array values (it should only include keys with immediate string/number/boolean values).
Example
[
{
id: 1,
person1: {
firstname: "test1",
lastname: 'singh',
address: {
state: "maharashtra",
}
}
},
{
id: 2,
person2: {
firstname: "test2",
lastname: 'rathod',
address: {
state: "kerala",
}
}
},
{
id: 3,
person3: {
firstname: "test3",
lastname: 'gokale',
address: {
state: "Tamilnadu",
}
}
}
]
Expected output
[
{
title: 'person1',
value: 'person.id'
},
{
title: 'person1',
value: 'person.firstname'
},
{
title: 'person1',
value: 'person.lastname'
},
{
title: 'person1',
value: 'person.address'
},
{
title: 'person1',
value: 'person.address.state'
},
...sameforOthers
]
Basically, I need a function that will get an array and will return an array of objects as a given above as expected output
Thanks in advance
I have come up with a solution. below is the link for code sandbox for the
https://codesandbox.io/s/heuristic-rubin-yy2cyy?file=/src/index.js:0-213same
const suggestions = [
{
id: 1,
person1: {
id: "1",
firstname: "test1",
lastname: "singh",
address: {
state: "maharashtra"
},
attributeId: "fhgfgh"
}
}
];
const typeList = ["string", "number", "boolean"];
const getLabelValue = (itemList, initalArr, parentId) => {
if (Array.isArray(itemList)) {
itemList.forEach((currentItem, idx) => {
const id = parentId ? `${parentId}.${idx}` : idx;
if (typeList.includes(typeof currentItem)) {
initalArr.push({
title: id,
value: id
});
} else {
getLabelValue(currentItem, initalArr, id);
}
});
} else {
let keys = Object.keys(itemList);
keys.forEach((currentKey) => {
let currentItem = itemList[currentKey];
const id = parentId ? `${parentId}.${currentKey}` : currentKey;
if (typeList.includes(typeof currentItem)) {
initalArr.push({
title: id,
value: id
});
} else {
getLabelValue(currentItem, initalArr, id);
}
});
}
return initalArr;
};
console.log(">>>>>>>>>", getLabelValue(suggestions, [], ""));

Could use someone's expertise with filtering my nested array by a certain value

I know there are a ton of "How to filter my array" questions. However, I'm still stuck.
I'm not too familiar with arrays and I'm hoping someone can help me with my particular situation.
I have an array that I'm trying to filter. I'm looking to return all data if "user.name" or "writers.name" equals "Adam". "user" will only ever have one name, while "writers" can have multiple.
[{
mediaId: '86699',
user: {
name: 'Adam',
id: '17622'
},
nodeType: 'testNode',
title: 'testTitle',
id: '23968',
writers: []
},
{
mediaId: '90547',
user: {
name: 'Jake',
id: '65936'
},
nodeType: 'testNode',
title: 'testTitleTwo',
id: '89960',
writers: [{
name: 'Adam',
id: '17622'
},
{
name: 'Steve',
id: '47622'
}]
},
{
mediaId: '99662',
user: {
name: 'James',
id: '22236'
},
nodeType: 'testNode',
title: 'testTitleThree',
id: '89960',
writers: [{
name: 'Paul',
id: '27622'
}]
}
]
Desired output:
[{
"mediaId": "86699",
"user": {
"name": "Adam",
"id": "17622"
},
"nodeType": "testNode",
"title": "testTitle",
"id": "23968",
"writers": []
},
{
"mediaId": "90547",
"user": {
"name": "Jake",
"id": "65936"
},
"nodeType": "testNode",
"title": "testTitleTwo",
"id": "89960",
"writers": [{
"name": "Adam",
"id": "17622"
},
{
"name": "Steve",
"id": "45389"
}]
}
]
Thank you in advance!!!
UPDATED: Everything is the same except that user and writers are now wrapped around properties.
[{
mediaId: '86699',
nodeType: 'testNode',
title: 'testTitle',
id: '23968',
properties: {
user: {
name: 'Adam',
id: '17622'
},
writers: []
}
}, {
mediaId: '90547',
nodeType: 'testNode',
title: 'testTitleTwo',
id: '89960',
properties: {
user: {
name: 'Jake',
id: '65936'
},
writers: [{
name: 'Adam',
id: '17622'
}, {
name: 'Steve',
id: '47622'
}]
}
}, {
mediaId: '99662',
nodeType: 'testNode',
title: 'testTitleThree',
id: '89960',
properties: {
user: {
name: 'James',
id: '22236'
},
writers: [{
name: 'Paul',
id: '27622'
}]
}
}]
To apply a filter, you are essentially iterating over each item in the array and seeing if it matches your criteria. Return true if you want it to stay, and return false if you want it to be filtered out.
So at the top-most layer, you have an array of objects, each of which appears to represent a node (judging by the "nodeType" property). We start with this:
const matches = array.filter(node => {
// criteria go here
return true; // or false
});
What are the criteria? Well it should remain if...
The node.user.name is "Adam"
Of the writers, at least one has writer.name === "Adam"
Let's define those.
const hasUserNameAdam = (node) => node?.user?.name === "Adam";
const hasWriterNameAdam = (writer) => writer?.name === "Adam";
We can do the same thing with the writer array to handle the second layer.
const arrayHasWriterNameAdam = writerArray.some(writer => hasWriterNameAdam(writer));
Now we just need to plug them in.
const matches = data.filter(node => {
const hasUserNameAdam = (node) => node?.user?.name === "Adam";
const hasWriterNameAdam = (writer) => writer?.name === "Adam";
const arrayHasWriterNameAdam = (writerArray) => writerArray.some(writer => hasWriterNameAdam(writer));
return hasUserNameAdam(node) || arrayHasWriterNameAdam(node?.writers);
});
And we can choose to refactor those inner functions back to being in line to clean things up, if we would like.
const matches = data.filter(node => node?.user?.name === "Adam" || node?.writers?.some(writer => writer?.name === "Adam"));
Update
Or with the updated object shape, the user and writers props are nested under the properties prop, so we only have to add the .properties layer to everywhere we access the user and writers properties to adapt.
const matches = data.filter(node => node?.properties?.user?.name === "Adam" || node?.properties?.writers?.some(writer => writer?.name === "Adam"));
input.filter(element => element.user.name === 'Adam' || element.writers.some(writer => writer.name === 'Adam'));
Try this:
const findAdam = arr => arr.filter(
element => element.properties.user.name === 'Adam' || element.properties.writers.some(writer => writer.name === 'Adam')
)

return the value of the matching items in an array

I have two arrays that I would like to compare and return a respective value of the ones that match.
Taking the 'id' variable as a reference, I want to return all the matching values of fastFood, but only the 'name'.
My expected result is to return Five Guys and KFC, but instead, it returns the entire object.
let id = ['1234'];
let fastFood = [
{_id:'4391', name: "McDonalds"},
{_id:'7654', name: "Burger King"},
{_id:'8765', name: "Dominos"},
{_id:'1234', name: "Five Guys"},
{_id:'9876', name: "Subway"},
{_id:'1234', name: "KFC"}
];
const findFastFood = ids.filter((item) => {
if (item._id.indexOf(id) !== -1) {
return item.name;
}
});
console.log(findFastFood);
Does this help?
let id = ['1234'];
let fastFood = [{
_id: '4391',
name: "McDonalds"
},
{
_id: '7654',
name: "Burger King"
},
{
_id: '8765',
name: "Dominos"
},
{
_id: '1234',
name: "Five Guys"
},
{
_id: '9876',
name: "Subway"
},
{
_id: '1234',
name: "KFC"
}
];
const findFastFood = fastFood.filter((item) => {
if (id.indexOf(item._id) !== -1) {
return item.name
}
}).map(obj => obj.name);
console.log(findFastFood);

Javascript filtering nested arrays

I'm trying to filter a on a nested array inside an array of objects in an Angular app. Here's a snippet of the component code -
var teams = [
{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] },
{ name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] },
{ name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];
What I'm trying to achieve is if I search for m5 for example my result should be -
var teams = [
{ name: 'Team1', members: [] },
{ name: 'Team2', members: [{ name: 'm5' }] },
{ name: 'Team3', members: [] }
];
So I've got teams and filteredTeams properties and in my search function I'm doing -
onSearchChange(event: any): void {
let value = event.target.value;
this.filteredTeams = this.teams.map(t => {
t.members = t.members.filter(d => d.name.toLowerCase().includes(value));
return t;
})
}
Now this does work to some extent however because I'm replacing the members it's destroying the array on each call (if that makes sense). I understand why this is happening but my question is what would be the best way to achieve this filter?
you were very close, the only thing that you did wrong was mutating the source objects in teams
basically you can use spread operator to generate a new entry and then return a whole new array with new values.
const teams = [
{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] },
{ name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] },
{ name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];
const value = 'm5';
const result = teams.map(t => {
const members = t.members.filter(d => d.name.toLowerCase().includes(value));
return { ...t, members };
})
console.log(result)
Check this. Instead of hard coded m5 pass your value.
const teams = [
{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] },
{ name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] },
{ name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];
const filteredTeams = teams.map(team => ({ name: team.name, members: team.members.filter(member => member.name.includes('m5')) }));
console.log(filteredTeams);
You are mutating the original objects, but you could assing new properties to the result object for mapping instead.
var teams = [{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] }, { name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] }, { name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }],
result = teams.map(o => Object.assign(
{},
o,
{ members: o.members.filter(({ name }) => name === 'm5') }
));
console.log(result);
console.log(teams);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try to seperate your filter function first:
const filterTeamMembers = (teams, filterArr) => {
const useFilter = filterArr.map(x => x.toLowerCase());
return teams.map(team => ({
...team,
members: team.members.filter(member => useFilter.includes(member.name))
}))
};
// =========== And then:
onSearchChange(event: any): void {
let value = event.target.value;
this.filteredTeams = filterTeamMembers(this.teams, [value]);
}

Combining two arrays based on properties

I have two arrays,
let student = [{ id: "weqwe", name: "john" }, { id: "wqeqweq", name: "doe" }]
let details = [
{ id: "2qweqweq", name: "larry", oName: "john" },
{ id: "231234qa", name: "jacob", oName: "john" },
{ id: "wetyrqwte", name: "jane", oName: "doe" }
]
I need to check through each object in details array and compare it with student array (compare with oName property in details array with name property in student array) and need to add an array of the details as on object property. Also need to remove the oName, I have tried in es6 but dynamically creating array and pushing gives only the last value, Please see the below expected output,
let output = [
{
id: "weqwe",
name: "john",
details: [
{ id: "2qweqweq", name: "larry" },
{ id: "231234qa", name: "jacob" }
]
},
{
id: "wqeqweq",
name: "doe",
details: [
{ id: "wetyrqwte", name: "jane" }
]
}
]
Thanks in advance !!
try this:
let student = [{ id: "weqwe", name: "john" }, { id: "wqeqweq", name: "doe" }]
let details = [
{ id: "2qweqweq", name: "larry", oName: "john" },
{ id: "231234qa", name: "jacob", oName: "john" },
{ id: "wetyrqwte", name: "jane", oName: "doe" }
];
let output = [{
id: "weqwe",
name: "john",
details: [
{ id: "2qweqweq", name: "larry" },
{ id: "231234qa", name: "jacob" }
]
},
{
id: "wqeqweq",
name: "doe",
details: [
{ id: "wetyrqwte", name: "jane" }
]
}
];
let result = student.map((obj) => {
obj.details = details.filter(o => o.oName === obj.name).map(({oName,...other}) =>other);
return obj;
});
console.log(result);
let student = [{id:"weqwe", name:"john"}, {id:"wqeqweq", name:"doe"}]
let details = [
{id:"2qweqweq", name:"larry", oName:"john"},
{id:"231234qa", name:"jacob", oName:"john"},
{id:"wetyrqwte", name:"jane", oName:"doe"}
]
let output= student.map(student=> {
const detailsObj = details.filter(({oName})=> oName === student.name)
return {...student, details: detailsObj.map(({oName, ...other})=> other)}
})
console.log(output)

Categories

Resources