comparing properties values inside an array of objects - javascript

so i'm doing some excercises as practice, since i'm a beginner, and i stumble into this problem that i can't solve, would anybody be kind to give me a hand?
i would like to make a function that returns how many people is 18 or older, this is what i've been trying but i'm a bit confused..
const examplePeople = [
{ name: 'John', age: 15 },
{ name: 'Jane', age: 16 },
{ name: 'Jack', age: 25 },
{ name: 'Ana', age: 18 },
{ name: 'Raul', age: 23 },
{ name: 'Pedro', age: 17 }
];
function countLegalPeople(people) {
for (i= 0; i >= people["age"] ; i++){
if (people[i]["age"] >= 18) {
return people[i];
}
}
}
console.log(countLegalPeople(examplePeople));

Why don't try Array.prototype.filter()
const examplePeople = [
{ name: 'John', age: 15 },
{ name: 'Jane', age: 16 },
{ name: 'Jack', age: 25 },
{ name: 'Ana', age: 18 },
{ name: 'Raul', age: 23 },
{ name: 'Pedro', age: 17 }
];
function countLegalPeople(people) {
return people.filter(p => p.age >= 18).length;
}
console.log(countLegalPeople(examplePeople));

I'd use reduce, where the accumulator is the number of objects found so far that pass the test:
const examplePeople = [
{ name: 'John', age: 15 },
{ name: 'Jane', age: 16 },
{ name: 'Jack', age: 25 },
{ name: 'Ana', age: 18 },
{ name: 'Raul', age: 23 },
{ name: 'Pedro', age: 17 }
];
const result = examplePeople.reduce((a, { age }) => a + (age >= 18), 0);
console.log(result);
With a for loop, you'd have to increment a more persistent variable, eg
const examplePeople = [
{ name: 'John', age: 15 },
{ name: 'Jane', age: 16 },
{ name: 'Jack', age: 25 },
{ name: 'Ana', age: 18 },
{ name: 'Raul', age: 23 },
{ name: 'Pedro', age: 17 }
];
let result = 0;
for (let i = 0; i < examplePeople.length; i++) {
if (examplePeople[i].age >= 18) {
result++;
}
}
console.log(result);
But array methods are generally more terse and elegant IMO.

The issue with your approach is that you are returning within your for loop. Whenever you return, your function will stop running (it essentially jumps out of your function), so, whenever you run into a person over the age of 18 you stop your loop and thus it cannot count any more people.
Instead, you can create a variable and set it to zero. This will count how many people of the age of 18 you have seen. To do this, you will need to add one to this variable each time you see a person of an age of 18 or higher. Then, once your for loop is complete, you can return this number.
See example below:
const examplePeople = [
{ name: 'John', age: 15 },
{ name: 'Jane', age: 16 },
{ name: 'Jack', age: 25 },
{ name: 'Ana', age: 18 },
{ name: 'Raul', age: 23 },
{ name: 'Pedro', age: 17 }
];
function countLegalPeople(people) {
let counter = 0; // number of people >= 18;
for (let i= 0; i < people.length; i++){ // loop through the array of people (using people.length)
if (people[i]["age"] >= 18) {
counter++; // age 1 to counter (same as counter = counter + 1)
}
}
return counter; // return the amount of people >= 18
}
console.log(countLegalPeople(examplePeople));

Your question was slightly confusing and could be taken two different ways, so if you are looking to return the total instances of people that are 18 and older in a new array, you would do something like this:
const examplePeople = [
{ name: 'John', age: 15 },
{ name: 'Jane', age: 16 },
{ name: 'Jack', age: 25 },
{ name: 'Ana', age: 18 },
{ name: 'Raul', age: 23 },
{ name: 'Pedro', age: 17 }
];
let adults = [];
for (let i = 0; i < examplePeople.length; i++) {
if (examplePeople[i].age >= 18) {
adults.push(examplePeople[i]);
}
}
console.log(adults);
you can also get the length with a simple:
console.log(adults.length);

Related

How to filter and map Array in JavaScript

The original array has several objects within it, each of these objects has three properties (timestamp, name and age).
If multiple timestamps in a row are 15 minutes apart, they will be grouped into the same object. Afterwards, a new property called end will be added, which will be the timestamp value of the last element of this group plus 15 minutes.
If there are not several elements in a row with a difference of 15 minutes between them, the end property will have the timestamp plus 15 minutes as a value.
This is my current code:
const data = [
{
timestamp: '2021-11-23T14:15:00+0000',
name: 'John',
age: 25,
},
{
timestamp: '2021-11-23T14:30:00+0000',
name: 'John',
age: 25,
},
{
timestamp: '2021-11-23T14:45:00+0000',
name: 'John',
age: 25,
},
{
timestamp: '2021-11-23T15:45:00+0000',
name: 'John',
age: 25,
},
{
timestamp: '2021-11-23T14:15:00+0000',
name: 'Anne',
age: 32,
},
{
timestamp: '2021-11-23T14:30:00+0000',
name: 'Anne',
age: 32,
},
{
timestamp: '2021-11-23T14:45:00+0000',
name: 'Anne',
age: 32,
},
{
timestamp: '2021-11-23T15:45:00+0000',
name: 'Anne',
age: 32,
},
]
const newArray = data.reduce((accumulator, current) => {
const end = new Date(Date.parse(current.timestamp) + 15 * 60 * 1000)
if (accumulator.length === 0) {
accumulator.push({
...current,
end,
})
} else {
const last = accumulator[accumulator.length - 1]
if (last.name === current.name && last.age === current.age) {
last.end = end
} else {
accumulator.push({
...current,
end,
})
}
}
return accumulator
}, [])
console.log(newArray)
However the end result of my code is not exactly what I want. I would like my result to be like this:
[
{
timestamp: '2021-11-23T14:15:00+0000',
name: 'John',
age: 25,
end: '2021-11-23T15:00:00+0000'
},
{
timestamp: '2021-11-23T15:45:00+0000',
name: 'John',
age: 25,
end: '2021-11-23T16:00:00+0000'
},
{
timestamp: '2021-11-23T14:15:00+0000',
name: 'Anne',
age: 32,
end: '2021-11-23T15:00:00+0000'
},
{
timestamp: '2021-11-23T15:45:00+0000',
name: 'Anne',
age: 32,
end: '2021-11-23T16:00:00+0000'
}
]
You could search for the last interval and update end if found. Otherwise add a new object.
const data = [{ timestamp: '2021-11-23T14:15:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T14:30:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T14:45:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T15:45:00+0000', name: 'John', age: 25 }, { timestamp: '2021-11-23T14:15:00+0000', name: 'Anne', age: 32 }, { timestamp: '2021-11-23T14:30:00+0000', name: 'Anne', age: 32 }, { timestamp: '2021-11-23T14:45:00+0000', name: 'Anne', age: 32 }, { timestamp: '2021-11-23T15:45:00+0000', name: 'Anne', age: 32 }]
const newArray = data.reduce((accumulator, current) => {
const
end = new Date(Date.parse(current.timestamp) + 15 * 60 * 1000).toISOString(),
item = accumulator.find(o =>
o.name === current.name &&
o.end === new Date(current.timestamp).toISOString()
);
if (item) item.end = end;
else accumulator.push({ ...current, end });
return accumulator;
}, [])
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.reduce() to get the required result as in your own code, but we can make a slight change to update the lastItem in the accumulator array if
The names are the same (lastItem.name === name)
The dates are within 15 minutes
If this condition isn't met we simply add to the accumulator array.
const data = [ { timestamp: '2021-11-23T14:15:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T14:30:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T14:45:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T15:45:00+0000', name: 'John', age: 25, }, { timestamp: '2021-11-23T14:15:00+0000', name: 'Anne', age: 32, }, { timestamp: '2021-11-23T14:30:00+0000', name: 'Anne', age: 32, }, { timestamp: '2021-11-23T14:45:00+0000', name: 'Anne', age: 32, }, { timestamp: '2021-11-23T15:45:00+0000', name: 'Anne', age: 32, }, ]
const result = data.reduce((acc, { timestamp, name, age }) => {
let lastItem = acc[acc.length - 1];
let end = new Date(Date.parse(timestamp) + 15*60*1000);
// If the current row matches just update the end time
if (lastItem && lastItem.name === name && (Date.parse(lastItem.end) - Date.parse(timestamp) >= 0)) {
lastItem.end = end;
} else {
acc.push({ timestamp, name, age, end });
}
return acc;
}, [])
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to compare and filter objects of array based on property value?

I have the following data structure:
persons: [
{ name: 'Joe', age: 20 },
{ name: 'Alex', age: 24 },
{ name: 'Joe', age: 34 },
{ name: 'Bob', age: 19 },
{ name: 'Alex', age: 56 },
]
I want to get the oldest person-object for each existing name. So the result of this example would be:
filteredPersons: [
{ name: 'Joe', age: 34 },
{ name: 'Bob', age: 19 },
{ name: 'Alex', age: 56 },
]
How can I achieve this? Note that the number of different names is not fixed.
You could take a Map and collect older ages for same names.
This soultion feature a function which compares two objects (or one object and a possible undefined) and if truthy and b.age is greater then a.age, it returns b, otherwise a.
At the end, only the values of the map are taken as result set.
const
older = (a, b) => b?.age > a.age ? b : a,
persons = [{ name: 'Joe', age: 20 }, { name: 'Alex', age: 24 }, { name: 'Joe', age: 34 }, { name: 'Bob', age: 19 }, { name: 'Alex', age: 56 }],
result = Array.from(persons.reduce((m, o) => m.set(
o.name,
older(o, m.get(o.name))
), new Map).values());
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
To do that in a single pass, you may employ Array.prototype.reduce() building up the Map that will have name as a key and store maximum age together with name as a value-object.
Once the Map is ready, you may extract its values with Map.prototype.values():
const src = [{name:'Joe',age:20},{name:'Alex',age:24},{name:'Joe',age:34},{name:'Bob',age:19},{name:'Alex',age:56},],
result = [...src
.reduce((acc, {name, age}) => {
const match = acc.get(name)
match ?
match.age = Math.max(age, match.age) :
acc.set(name, {name,age})
return acc
}, new Map)
.values()
]
console.log(result)
.as-console-wrapper{min-height:100%;}
Simply reduce the array and for each person in the array, check if the item has been encountered before, if so keep the oldest one, otherwise just keep the current object:
let results = persons.reduce((acc, person) => { // for each person in persons
if(!acc[person.name] || acc[person.name].age < person.age) { // if this person has never been encountered before (acc[person.name]) or if the already encountered one is younger (acc[person.name].age < person.age)
acc[person.name] = person; // store the current person under the name
}
return acc;
}, Object.create(null)); // Object.create(null) instead of {} to create a prototypeless object
This will return an object containing the oldest persons in this format { name: person, name: person, ... }. If you want to get them as an array, call Object.values like so:
let arrayResults = Object.values(results);
Demo:
let persons = [{ name: 'Joe', age: 20 }, { name: 'Alex', age: 24 }, { name: 'Joe', age: 34 }, { name: 'Bob', age: 19 }, { name: 'Alex', age: 56 }];
let results = persons.reduce((acc, person) => {
if(!acc[person.name] || acc[person.name].age < person.age) {
acc[person.name] = person;
}
return acc;
}, Object.create(null));
let arrayResults = Object.values(results);
console.log("results:", results);
console.log("arrayResults:", arrayResults);
Hope this is more understandable for you.
const persons = [
{ name: 'Joe', age: 20 },
{ name: 'Alex', age: 24 },
{ name: 'Joe', age: 34 },
{ name: 'Bob', age: 19 },
{ name: 'Alex', age: 56 },
]
let personsObj = {}, mxPersons = []
persons.forEach(person => {
if (personsObj[person.name] == undefined) {
personsObj[person.name] = person.age
} else {
personsObj[person.name] = Math.max(person.age, personsObj[person.name])
}
})
for (const [key, value] of Object.entries(personsObj)) {
mxPersons.push({
name: key,
age: value
})
}
console.log(mxPersons)
The oldest people per name can be obtained by first grouping all people based on their name, then take the oldest person of each group.
This answer does introduce two helper functions groupBy and maxBy, which add some overhead but are really usefull in general.
const people = [
{ name: 'Joe', age: 20 },
{ name: 'Alex', age: 24 },
{ name: 'Joe', age: 34 },
{ name: 'Bob', age: 19 },
{ name: 'Alex', age: 56 },
];
const oldestPeople = Array
.from(groupBy(people, person => person.name).values())
.map(people => maxBy(people, person => person.age));
console.log(oldestPeople);
function groupBy(iterable, fn) {
const groups = new Map();
for (const item of iterable) {
const key = fn(item);
if (!groups.has(key)) groups.set(key, []);
groups.get(key).push(item);
}
return groups;
}
function maxBy(iterable, fn) {
let max, maxValue;
for (const item of iterable) {
const itemValue = fn(item);
if (itemValue <= maxValue) continue;
[max, maxValue] = [item, itemValue];
}
return max;
}

how to replace array of object with an object in javascript without repeating

let a = [{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
let case1 = { name: "ben", age: 10 }
let case2={ name: "jack", age: 30 }
case1:
i expect the result to be
[{ name: "ben", age: 10 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
where "ben" is existing so it replaces age to 10
case2:
i expect the result to be
[{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 },{ name: "jack", age: 30 }]
where "jack" is not there in the array so it adds to the array
how to write a function which does this functionality
Yours is a good case for Array.prototype.findIndex (MDN), which is like Array.prototype.find but returns the found index instead of the item.
let a = [{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
let case1 = { name: "ben", age: 10 }
let case2 = { name: "jack", age: 30 }
const arrayUpsert = function (array, object) {
const objectIndex = array.findIndex(item => item.name == object.name)
if (objectIndex == -1) {
array.push(object)
} else {
array[objectIndex] = { ...array[objectIndex], ...object }
}
return array
}
console.log(arrayUpsert(a, case1))
console.log(arrayUpsert(a, case2))
/* [
{ name: 'ben', age: 10 },
{ name: 'jeffrey', age: 10 },
{ name: 'daniel', age: 20 }
]
[
{ name: 'ben', age: 10 },
{ name: 'jeffrey', age: 10 },
{ name: 'daniel', age: 20 },
{ name: 'jack', age: 30 }
] */
Can be done with a for loop as well.
function untitled(original, newObj) {
for (let index = 0; index < original.length; index++) {
if (original.name && newObj.name === a[index].name) {
original[index] = {...newObj};
console.log(original); return;
}
}
original.push(newObj); console.log(original);
}
let a = [{ name: "ben", age: 25 }, { name: "jeffrey", age: 10 },{ name: "daniel", age: 20 }]
let case1 = { name: "ben", age: 10 }
let case2 = { name: "jack", age: 30 }
untitled(a, case1);
untitled(a, case2);
I'm using ramda library in my solution:-
Check whether the key exist in any of the object in array by
idx = R.findIndex(R.propEq('name', 'ben'), a). If idx<0 then we can directly push the object else go to the next step.
We have the index(idx), we just have to do a[idx].age="--".

increment the duplicate value of object in any array of objects in java script

I have a 5 age fields where user can enter same value they are not validating
while sending to the API. I have to increment the duplicate ages in ech object.
for ex - if user gives ages like 10, 11, 10, 10, 20 i need it as 10,11,12,13,20 like this
Here is the variable having duplicate:
var family = [
{
name: "Mike",
age: 10
},
{
name: "Matt"
age: 13
},
{
name: "Nancy",
age: 13
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 23
},
{
name: "Nancy",
age: 22
}
];
where every duplicate values comes i have to increment by checking all the ages in each object i need out put like this --> here age 13 and 22 is duplicating i have to check all ages and i have to increment 2nd repeted age by +1 -->
var family = [
{
name: "Mike",
age: 10
},
{
name: "Matt"
age: 13
},
{
name: "Nancy",
age: 14
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 23
},
{
name: "Nancy",
age: 24
}
];
note my array will have only 5 objects
Try with below code. Hope this will be help u.
var family = [
{
name: "Mike",
age: 10
},
{
name: "Matt",
age: 13
},
{
name: "Nancy",
age: 13
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 23
},
{
name: "Nancy",
age: 22
}
];
var ind = [];
family.forEach(a => {
cur = a.age;
while (ind[cur] === 1) {
cur++;
}
ind[cur] = 1;
a.age = cur;
});
family.forEach(a => console.log(a.age));
Another update:
var order = family.map((person, index) => {
return { index, person };
}).sort((a, b) => {
if (a.person.age === b.person.age) {
return a.index - b.index;
}
return a.person.age > b.person.age ? 1 : -1;
});
var prevAge = 0;
order.forEach(item => {
if (item.person.age <= prevAge) {
item.person.age = ++prevAge;
}
prevAge = item.person.age;
family.filter(f => f.name === item.person.name)[0].age = item.person.age;
});
Please, try the different cases I put in the demo and check if the results are what you would expect.
Stackblitz: https://stackblitz.com/edit/typescript-far3zq

Compare two arrays to get count of properties

I have two arrays that I would like to compare and provide a count of the items in the master list.
The master list might look like this:
{ name: 'Jon', age: 34 },
{ name: 'Steve', age: 33 },
{ name: 'Mark', age: 34 },
{ name: 'Jon', age: 35 }
The Filter list gets all possible names / ages from the database. Some might not have any entries. Each of these lists are getting pulled from an API individually. I will combine them into one array:
{ users:
[{ username: 'Jon' },
{ userName: 'Steve' },
{ username: 'Mark' },
{ username: 'Mike' }],
ages:
[{age: 33},
{age: 34},
{age: 35},
{age: 36}]
}
What I would like to do is be able to count how many of each name I have
Jon - 2, Steve - 1, Mark - 1, Mike - 0
33 - 1, 34 - 2, 35 - 1
Here is a generic approach. You provide the data and the field you want to count.
var data = [
{ name: 'Jon', age: 34 },
{ name: 'Steve', age: 33 },
{ name: 'Mark', age: 34 },
{ name: 'Jon', age: 35 }
];
function countUnique(items, property) {
return items.reduce(function(map, item) {
if (item.hasOwnProperty(property)) {
map[item[property]] = (map[item[property]] || 0) + 1;
}
return map;
}, {});
}
console.log(countUnique(data, 'name')); // Object {Jon: 2, Steve: 1, Mark: 1}
console.log(countUnique(data, 'age')); // Object {33: 1, 34: 2, 35: 1}
Filtering
If you want to filter a list of users by conditions, you can define an array of filter objects as seen below. When filtering a list of items, you usually will provide a predicate function to execute on the current item in the filter call. This function returns a boolean value which determines whether or not the item meets the conditions of the function.
var users = [
{ name: 'Jon', age: 34 },
{ name: 'Steve', age: 33 },
{ name: 'Mark', age: 34 },
{ name: 'Jon', age: 35 }
];
var filters = [{
name: 'users',
predicate : function(user) {
return [ 'Jon', 'Mark', 'Mike' ].indexOf(user.name) > -1;
}
}, {
name: 'ages',
predicate : function(user) {
return user.age >= 34 && user.age <= 36;
}
}];
print(filterFactory(users, getFiltersByName(filters, ['users', 'ages'])));
function getFiltersByName(filters, names) {
return filters.filter(function(filter) {
return names.indexOf(filter.name) > -1;
});
}
function filterFactory(items, filters) {
return items.filter(function(item) {
return filters.some(function(filter) {
try { return filter.predicate.call(undefined, item); }
catch (e) { throw new Error('predicate undefined for filter: ' + filter.name); }
});
});
}
function print(obj) {
document.body.innerHTML = JSON.stringify(obj, undefined, ' ');
}
body { font-family: monospace; white-space: pre }
Something like this would do. Here is a fiddle http://jsfiddle.net/5jkqv6k3/
var data = [
{ name: 'Jon', age: 34 },
{ name: 'Steve', age: 33 },
{ name: 'Mark', age: 34 },
{ name: 'Jon', age: 35 }
];
var key = function(obj) {
// Some unique object-dependent key
return obj.name; // Just an example
};
var dict = {};
for (var i = 0; i < data.length; i++) {
if (dict[key(data[i])])
dict[key(data[i])] = dict[key(data[i])] + 1;
else
dict[key(data[i])] = 1;
}
console.log(dict);
Using angularJs (because you're using it as you said) you can do this:
var countNamesList = {};
var countAgesList = {};
angular.forEach(masterList, function(value, index) {
countNamesList[masterList[index].name] =
(!angular.isUndefined(countNamesList[masterList[index].name])) ?
countNamesList[masterList[index].name] + 1 : 1;
countAgesList[masterList[index].age] =
(!angular.isUndefined(countAgesList[masterList[index].age])) ?
countAgesList[masterList[index].age] + 1 : 1;
});
console.log(countNamesList);
console.log(countAgesList);
JSFIDDLE
Mr. Polywhirl's answer is your best option on counting.
Now here's how you can filter:
var master = [
{ name: 'Jon', age: 34 },
{ name: 'Steve', age: 33 },
{ name: 'Mark', age: 34 },
{ name: 'Jon', age: 35 }
];
var filter = {
users: [
{ username: 'Jon' },
{ username: 'Mark' },
{ username: 'Mike' }
], ages: [
{ age: 34 },
{ age: 35 },
{ age: 36 }
]
};
function filterByNameAndAge(obj) {
return filter.users.some(function(user) {
return user.username === obj.name;
}) && filter.ages.some(function(age) {
return age.age === obj.age;
});
}
console.log(master.filter(filterByNameAndAge));
Currently it accepts only objects with matching name and age. Replace the && inside filterByNameAndAge by || if it should accept objects with matching name or age.

Categories