How to get all objects and count booleans (JS) - javascript

Let it be like this for example:
let data = {
first: {
surname: 'Miller',
age: 37,
gender: 'male',
stealer: true
},
second: {
surname: 'Connor',
age: 28,
gender: 'male',
stealer: true
},
third: {
surname: 'Smith',
age: 13,
gender: 'female',
stealer: false
}
}
How can I get everything at once and count booleans of false, without the need to manually enter each one individually?

You can use Object.values to retrieve the values as an array and Array.prototype.reduce to count:
let data = { first: { surname: 'Miller', age: 37, gender: 'male', stealer: true }, second: { surname: 'Connor', age: 28, gender: 'male', stealer: true }, third: { surname: 'Smith', age: 13, gender: 'female', stealer: false } };
const result = Object.values(data).flatMap(el => Object.values(el)).reduce((acc, el) => acc + (el === false), 0);
console.log(result);

Related

Javascript array gets sorted before sort statement [duplicate]

This question already has answers here:
Is Chrome’s JavaScript console lazy about evaluating objects?
(7 answers)
Closed 9 months ago.
Edit: This seems related to the way the chrome console handles object evaluation as noted by
jsN00b
original here
I'm sorting an array by name and then by age, logging the array three times:
Once right after initialization,
second and third time is after sorting the array by name and then age respectively.
The first console.log() call however, prints the array in its sorted state, but what I expected to have is the array in it's unsorted state.
Not sure if this is related to the way JavaScript handles array in memory or is is it a bug?
Code:
function byField(field) {
return (objA, objB) => (objA[field] > objB[field] ? 1 : -1);
}
let users = [
{ name: "John", age: 20, surname: "Johnson" },
{ name: "Pete", age: 18, surname: "Peterson" },
{ name: "Ann", age: 19, surname: "Hathaway" },
];
console.log(users);
users.sort(byField("name"));
console.log(users);
users.sort(byField("age"));
console.log(users);
.as-console-wrapper { max-height: 100% !important; top: 0 }
Expected output:
//unsorted
[
{ name: "John", age: 20, surname: "Johnson" },
{ name: "Pete", age: 18, surname: "Peterson" },
{ name: "Ann", age: 19, surname: "Hathaway" },
];
//by name
[
{ name: "Ann", age: 19, surname: "Hathaway" },
{ name: "John", age: 20, surname: "Johnson" },
{ name: "Pete", age: 18, surname: "Peterson" },
];
//by age
[
{ name: "Pete", age: 18, surname: "Peterson" },
{ name: "Ann", age: 19, surname: "Hathaway" },
{ name: "John", age: 20, surname: "Johnson" },
];
Actual Output:
//unsorted
[
{ name: "Pete", age: 18, surname: "Peterson" },
{ name: "Ann", age: 19, surname: "Hathaway" },
{ name: "John", age: 20, surname: "Johnson" },
];
//by name
[
{ name: "Pete", age: 18, surname: "Peterson" },
{ name: "Ann", age: 19, surname: "Hathaway" },
{ name: "John", age: 20, surname: "Johnson" },
];
//by age
[
{ name: "Pete", age: 18, surname: "Peterson" },
{ name: "Ann", age: 19, surname: "Hathaway" },
{ name: "John", age: 20, surname: "Johnson" },
];
Method Array.prototype.sort does mutate your initial array. For fix this problem you need to create copy of array and then sort this copy.
It is like follow example:
[...users].sort(byField("name"));

Count duplicates in an array of objects and sum up values located in the objects

I have an array of objects that looks like this:
const users = [{name: 'John', gender: 'Male', orders: 20},
{name: 'Doe', gender: 'Male', orders: 8},
{name: 'Ada', gender: 'Female', orders: 10},
{name: 'David', gender: 'Male', orders: 30}];
I need to count the number of duplicate genders and sum up the amount of orders based on gender located in the objects. I would like the final array to look like this:
[{gender: 'Male', count: 3, totalOrders: 58}, {gender: 'Female', count: 1, totalOrders: 10}]
This is the code I have so far:
const usersGender = users.map((user) => user.gender);
const result = Object.values(usersGender.reduce((a, b) => {
a[b] = a[b] || [b, 0];
a[b][1]++;
return a;
},{})).map(item => ({gender: item[0], count : item[1]}));
console.log(result);
My output from the code above is:
[{ gender: 'Male', count: 3 }, { gender: 'Female', count: 1 }]
Thank you.
You could collect with an object and get the values from it.
const
users = [{ name: 'John', gender: 'Male', orders: 20 }, { name: 'Doe', gender: 'Male', orders: 8 }, { name: 'Ada', gender: 'Female', orders: 10 }, { name: 'David', gender: 'Male', orders: 30 }],
result = Object.values(users.reduce((r, { gender, orders }) => {
r[gender] ??= { gender, count: 0, totalOrders: 0 };
r[gender].count++;
r[gender].totalOrders += orders;
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Javascript sort obj by compound key

I have an object so defined:
{
_id: "5d406a171ed43384972f04b5",
index: 0,
age: 28,
eyeColor: "brown",
name: {
first: "Myra",
last: "Navarro"
},
company: "SUSTENZA",
email: "myra.navarro#sustenza.net"
}
I would need to be able to do the search on all keys, even in compound keys like name.
For example I have a search string name.first and the like, it could be even deeper and compound objects.
I managed to do this, but on name.first for example I am failing to get it to work.
Can you give me a hand?
let datatable = [
{
_id: "5d406a171ed43384972f04b5",
index: 0,
age: 28,
eyeColor: "brown",
name: {
first: "Myra",
last: "Navarro"
},
company: "SUSTENZA",
email: "myra.navarro#sustenza.net"
},
{
_id: "5d406a170db0f4b04d9a9acf",
index: 1,
age: 23,
eyeColor: "blue",
name: {
first: "Harriett",
last: "Tanner"
},
company: "VALPREAL",
email: "harriett.tanner#valpreal.com"
},
{
_id: "5d406a17e95da8ff80a759c5",
index: 2,
age: 39,
eyeColor: "blue",
name: {
first: "Vega",
last: "Hanson"
},
company: "BEDLAM",
email: "vega.hanson#bedlam.tv"
},
{
_id: "5d406a175505da190e6875ec",
index: 3,
age: 31,
eyeColor: "blue",
name: {
first: "Rosemary",
last: "Fields"
},
company: "QUAILCOM",
email: "rosemary.fields#quailcom.me"
},
{
_id: "5d406a17ea96044c027f4e50",
index: 4,
age: 27,
eyeColor: "brown",
name: {
first: "Dale",
last: "Wilkinson"
},
company: "QIAO",
email: "dale.wilkinson#qiao.org"
},
{
_id: "5d406a17c5fff1ff6653a555",
index: 5,
age: 25,
eyeColor: "blue",
name: {
first: "Beatrice",
last: "Contreras"
},
company: "ZENOLUX",
email: "beatrice.contreras#zenolux.us"
},
{
_id: "5d406a17a199efcba25e1f26",
index: 6,
age: 34,
eyeColor: "blue",
name: {
first: "Hancock",
last: "Wynn"
},
company: "PLASMOS",
email: "hancock.wynn#plasmos.co.uk"
},
{
_id: "5d406a17019a2a4544a4f134",
index: 7,
age: 40,
eyeColor: "blue",
name: {
first: "Brown",
last: "Stanton"
},
company: "SNACKTION",
email: "brown.stanton#snacktion.name"
},
{
_id: "5d406a17e516dd71af8210d4",
index: 8,
age: 39,
eyeColor: "blue",
name: {
first: "Barnes",
last: "Dunn"
},
company: "PORTALINE",
email: "barnes.dunn#portaline.ca"
},
{
_id: "5d406a17516936a025b73c33",
index: 9,
age: 34,
eyeColor: "green",
name: {
first: "Blanche",
last: "Cherry"
},
company: "ISOSWITCH",
email: "blanche.cherry#isoswitch.io"
},
{
_id: "5d406a17527a4d2c6a7897dd",
index: 10,
age: 33,
eyeColor: "blue",
name: {
first: "Gilliam",
last: "Farley"
},
company: "AMTAS",
email: "gilliam.farley#amtas.biz"
},
{
_id: "5d406a175ff11478c416c30b",
index: 11,
age: 26,
eyeColor: "brown",
name: {
first: "Laura",
last: "Short"
},
company: "FISHLAND",
email: "laura.short#fishland.info"
},
{
_id: "5d406a1738181b471847339a",
index: 12,
age: 20,
eyeColor: "brown",
name: {
first: "Moreno",
last: "Barber"
},
company: "KEENGEN",
email: "moreno.barber#keengen.net"
},
{
_id: "5d406a17a6bcae6fe3ad1735",
index: 13,
age: 30,
eyeColor: "brown",
name: {
first: "Fischer",
last: "French"
},
company: "INCUBUS",
email: "fischer.french#incubus.com"
},
{
_id: "5d406a17600ca53e8f63f263",
index: 14,
age: 30,
eyeColor: "brown",
name: {
first: "Donaldson",
last: "Carr"
},
company: "SUNCLIPSE",
email: "donaldson.carr#sunclipse.tv"
},
{
_id: "5d406a17530655789a27174f",
index: 15,
age: 35,
eyeColor: "green",
name: {
first: "Sophia",
last: "Payne"
},
company: "PRISMATIC",
email: "sophia.payne#prismatic.me"
},
{
_id: "5d406a175dbc687b4c7669d8",
index: 16,
age: 34,
eyeColor: "green",
name: {
first: "Simone",
last: "Pollard"
},
company: "DIGIGEN",
email: "simone.pollard#digigen.org"
},
{
_id: "5d406a179f35ed326a6a5567",
index: 17,
age: 28,
eyeColor: "green",
name: {
first: "Yvette",
last: "Daugherty"
},
company: "CHILLIUM",
email: "yvette.daugherty#chillium.us"
}
];
const sortAsc = true;
const sortField = "name.first";//index,eyeColor
var result = datatable.sort((a, b) => {
let [x, z] = sortAsc ? [a, b] : [b, a];
//console.log(x[sortField], z[sortField], x[sortField] > z[sortField] ? 1 : -1);
return x[sortField] > z[sortField] ? 1 : -1;
});
console.log(result);
Edit:
It seems to work like this, but I would like to write it in a more compact form and possibly reduce the computation time.
Do you think it is possible?
var result = datatable.sort((a, b) => {
let [x, z] = sortAsc ? [a, b] : [b, a];
const arraySplit = sortField.split('.');
var vX = arraySplit.reduce((a, b) => a[b], x);
var vZ = arraySplit.reduce((a, b) => a[b], z);
return vX > vZ ? 1 : -1;
});
First issue is that javascript doesn't automatically access children using dots.
If you want to implement that, here are some solutions:
Access object child properties using a dot notation string
Next, once you have the value you want to compare with.
You need to use a special string compare function if the value is a string (use typeof to check). Or use valA - valB so that you get 1, 0, and -1 as the return values to sort with.
I hope this is what you need. The child function makes what you need. You have the explanation in the comments.
let datatable = [
{
_id: "5d406a171ed43384972f04b5",
index: 0,
age: 28,
eyeColor: "brown",
name: {
first: "Myra",
last: "Navarro"
},
company: "SUSTENZA",
email: "myra.navarro#sustenza.net"
},
{
_id: "5d406a170db0f4b04d9a9acf",
index: 1,
age: 23,
eyeColor: "blue",
name: {
first: "Harriett",
last: "Tanner"
},
company: "VALPREAL",
email: "harriett.tanner#valpreal.com"
},
{
_id: "5d406a17e95da8ff80a759c5",
index: 2,
age: 39,
eyeColor: "blue",
name: {
first: "Vega",
last: "Hanson"
},
company: "BEDLAM",
email: "vega.hanson#bedlam.tv"
},
{
_id: "5d406a175505da190e6875ec",
index: 3,
age: 31,
eyeColor: "blue",
name: {
first: "Rosemary",
last: "Fields"
},
company: "QUAILCOM",
email: "rosemary.fields#quailcom.me"
},
{
_id: "5d406a17ea96044c027f4e50",
index: 4,
age: 27,
eyeColor: "brown",
name: {
first: "Dale",
last: "Wilkinson"
},
company: "QIAO",
email: "dale.wilkinson#qiao.org"
},
{
_id: "5d406a17c5fff1ff6653a555",
index: 5,
age: 25,
eyeColor: "blue",
name: {
first: "Beatrice",
last: "Contreras"
},
company: "ZENOLUX",
email: "beatrice.contreras#zenolux.us"
},
{
_id: "5d406a17a199efcba25e1f26",
index: 6,
age: 34,
eyeColor: "blue",
name: {
first: "Hancock",
last: "Wynn"
},
company: "PLASMOS",
email: "hancock.wynn#plasmos.co.uk"
},
{
_id: "5d406a17019a2a4544a4f134",
index: 7,
age: 40,
eyeColor: "blue",
name: {
first: "Brown",
last: "Stanton"
},
company: "SNACKTION",
email: "brown.stanton#snacktion.name"
},
{
_id: "5d406a17e516dd71af8210d4",
index: 8,
age: 39,
eyeColor: "blue",
name: {
first: "Barnes",
last: "Dunn"
},
company: "PORTALINE",
email: "barnes.dunn#portaline.ca"
},
{
_id: "5d406a17516936a025b73c33",
index: 9,
age: 34,
eyeColor: "green",
name: {
first: "Blanche",
last: "Cherry"
},
company: "ISOSWITCH",
email: "blanche.cherry#isoswitch.io"
},
{
_id: "5d406a17527a4d2c6a7897dd",
index: 10,
age: 33,
eyeColor: "blue",
name: {
first: "Gilliam",
last: "Farley"
},
company: "AMTAS",
email: "gilliam.farley#amtas.biz"
},
{
_id: "5d406a175ff11478c416c30b",
index: 11,
age: 26,
eyeColor: "brown",
name: {
first: "Laura",
last: "Short"
},
company: "FISHLAND",
email: "laura.short#fishland.info"
},
{
_id: "5d406a1738181b471847339a",
index: 12,
age: 20,
eyeColor: "brown",
name: {
first: "Moreno",
last: "Barber"
},
company: "KEENGEN",
email: "moreno.barber#keengen.net"
},
{
_id: "5d406a17a6bcae6fe3ad1735",
index: 13,
age: 30,
eyeColor: "brown",
name: {
first: "Fischer",
last: "French"
},
company: "INCUBUS",
email: "fischer.french#incubus.com"
},
{
_id: "5d406a17600ca53e8f63f263",
index: 14,
age: 30,
eyeColor: "brown",
name: {
first: "Donaldson",
last: "Carr"
},
company: "SUNCLIPSE",
email: "donaldson.carr#sunclipse.tv"
},
{
_id: "5d406a17530655789a27174f",
index: 15,
age: 35,
eyeColor: "green",
name: {
first: "Sophia",
last: "Payne"
},
company: "PRISMATIC",
email: "sophia.payne#prismatic.me"
},
{
_id: "5d406a175dbc687b4c7669d8",
index: 16,
age: 34,
eyeColor: "green",
name: {
first: "Simone",
last: "Pollard"
},
company: "DIGIGEN",
email: "simone.pollard#digigen.org"
},
{
_id: "5d406a179f35ed326a6a5567",
index: 17,
age: 28,
eyeColor: "green",
name: {
first: "Yvette",
last: "Daugherty"
},
company: "CHILLIUM",
email: "yvette.daugherty#chillium.us"
}
];
const sortAsc = true;
const sortField = "name.first";//index,eyeColor
var result = datatable.sort((a, b) => {
let [x, z] = sortAsc ? [a, b] : [b, a];
//console.log(x[sortField], z[sortField], x[sortField] > z[sortField] ? 1 : -1);
//return x[sortField] > z[sortField] ? 1 : -1;
return child(x, sortField) > child(z, sortField) ? 1: -1;
});
console.log(result);
function child(obj, str){
//take dot-separated chain of properties' names and split them into an array
const props = str.split('.');
let child = obj;
//looop through all properties' names and get the access to the following [Object] children sequentially
props.forEach((prop)=> child = child[prop]);
return child;
}
Option 1:
const objRoute = sortField.split(".");
const getValue = obj => objRoute.reduce((v, c) => v[c], obj);
const result = datatable.sort((a, b) =>
sortAsc
? getValue(a).localeCompare() - getValue(b).localeCompare()
: getValue(b).localeCompare() - getValue(a).localeCompare()
);
Option 2:
Use eval, eval() evaluates the expression.
It is recommended to use this function with caution:
const result = datatable.sort((a, b, i) => eval(`a.${sortField}`) - eval(`b.${sortField}`));

Mapping data from two arrays which have different lengths and creating another array

I have two arrays which have two different lengths.
For example:
var array1 = [{name: 'Yuri', age: 2, gender: 'Male'}, {name: 'Akit', age: 19, gender: 'Male'}, {name: 'Kean', age: 14, gender: 'Female'}, {name: 'Jan', age: 29, gender: 'Male'}, {name: 'Max', age: 25, gender: 'Male'}, {name: 'Suzy', age: 20, gender: 'Female'}];
var array2 = [{name: 'Jan', gender: 'Male', occupation: 'Designer'}, {name: 'Max', gender: 'Male', occupation: 'Developer'}, {name: 'Suzy', gender: 'Female', occupation: 'Tester'}];
array1's length is 5 and array2's length is 3. I want to run a loop on both arrays and match the name. If the name matches then I want to extract the that particular object from 2nd array. As they have different lengths loop is breaking at the first array length and not reaching 2nd array's last element. I am running the for loop based on array2 length. Please help me with this.
Expected result:
Name of both arrays should be matched and create another array as below
var array3 = [{name: 'Jan',age: 29, gender: 'Male', occupation: 'Designer'},
same for other objects]
You could take a Set for one array's names and filter the second array.
var array1 = [{name: 'Yuri', age: 9, gender: 'Male'}, {name: 'Akit', age: 19, gender: 'Male'}, {name: 'Kean', age: 14, gender: 'Female'}, {name: 'Jan', gender: 'Male'}, {name: 'Max', gender: 'Female'}],
array2 = [{name: 'Jan', age: 9, gender: 'Male'}, {name: 'Max', age: 19, gender: 'Male'}, {name: 'Suzy', age: 14, gender: 'Female'}],
set2 = new Set(array2.map(({ name }) => name)),
result = array1.filter(o => set2.has(o.name));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var arr1 = [{name: 'Jan', age: 19}, {name: 'Suzy', age: 29}, {name: 'Peter', age: 39}, {name: 'Bart', age: 49}, {name: 'John', age: 59}];
var arr2 = [{name:'Kean', job: 'Technician'},{name:'Nick', job:'Mathematics'},{name: 'Jan', job: 'Tester'}, {name: 'Suzy', job:'Developer'}, {name: 'Peter', job: 'Scrum master'}];
result = arr1.map(x=> {
y = arr2.find(z=> x.name == z.name);
x.job = y ? y.job : undefined;
return x;
});

Javascript multiple filters array

My question is extension to this question javascript filter array multiple conditions
from that question if filter object is
{address: 'England', name: 'Mark'};
and array is
var users = [{
name: 'John',
email: 'johnson#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom#mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark#mail.com',
age: 28,
address: 'England'
}
];
so the answer is
[
{
"name": "Mark",
"email": "mark#mail.com",
"age": 28,
"address": "England"
}
]
which is absolutely fine but my question is array has to be filtered for the filter object properties value
for example my filter object will be {address: 'England', name: ''} now this has to filter the array for all names and address England
You'd use filter on users and every on the filter object's entries
const filter = {address: 'England', name: 'Mark'};
const res = users.filter(user =>
Object.entries(filter)
.every(([k,v]) => v === '' || user[k] === v)
);
console.log(res);
<script>
var users = [{
name: 'John',
email: 'johnson#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom#mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark#mail.com',
age: 28,
address: 'England'
}
];
</script>
From the example in the post you mention, just continue if the filter is blank
var filter = {address: 'England', name: ''}
var users = [{
name: 'John',
email: 'johnson#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom#mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark#mail.com',
age: 28,
address: 'England'
}
];
users = users.filter(function(item) {
for (var key in filter) {
if (filter[key] == "") continue; // added this:
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
console.log(users)
You can use a combination of filter and every with some ternary logic to determine if the filter value is empty to get all.
var users = [{
name: 'John',
email: 'johnson#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom#mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark#mail.com',
age: 28,
address: 'England'
}
];
var filter1 = {address: 'England', name: 'Mark'};
var filter2 = {address: 'England', name: ''};
function findResults(input, filterObj){
return input.filter(
item => Object.keys(filterObj)
.every(r => filterObj[r].length
? item[r] == filterObj[r]
: true)
)
}
console.log('with address and name', findResults(users,filter1));
console.log('with address only', findResults(users,filter2));
If I understand your question correctly you need following output.
If this what you are looking for Array.filter should suffice your use case.
Take a look at the code sandbox where I have created a function filterByObj which takes arr, filterObj as arguments and returns given output for { address: "England", name: "" }
You need you filter for this case.
var filter1 = {
address: 'England',
name: 'Mark'
};
var filter2 = {
address: 'England',
name: ''
};
var users = [
{
name: 'John',
email: 'johnson#mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom#mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark#mail.com',
age: 28,
address: 'England'
}
];
function filterUser(arr, obj) {
return arr.filter(function(item) {
return (
(obj.address === '' || item.address === obj.address) &&
(obj.name === '' || item.name === obj.name)
);
});
}
console.log(filterUser(users, filter1));
console.log(filterUser(users, filter2));

Categories