How to Group array of objects with same keys using javascripts? - javascript

I want to make an array of objects grouped by the date property.
let data = [
{ Age: "(60-100)", Date: "28/05/20" },
{ Age: "(60-100)", Date: "28/05/20" },
{ Age: "(4-6)", Date: "28/05/20" },
{ Age: "(60-100)", Date: "29/05/20" },
{ Age: "(38-43)", Date: "29/05/20" },
{ Age: "(4-6)", Date: "29/05/20" },
{ Age: "(38-43)", Date: "30/05/20" },
{ Age: "(38-43)", Date: "30/05/20" }
];
I want the output like
result = [
{ Date: "28/05/20", "(60-100)": 2, "(4-6)": 1 },
{ Date: "29/05/20", "(38-43)": 1, "(4-6)": 1, "(60-100)": 1 },
{ Date: "30/05/20", "(38-43)": 2 },
]

Try this:
function groupByDate(data){
let groupedData = [];
data.forEach(element => {
//Search for the object containing the specified date
let objIndex = groupedData.findIndex(object => {return object.Date == element.Date;})
//If date is not created, create it
if (objIndex == -1){
groupedData.unshift({Date: element.Date})
objIndex = 0;
}
//If age is not created, create it. Else add 1 to specified age.
if(typeof groupedData[objIndex][element.Age] == 'undefined'){
groupedData[objIndex][element.Age] = 1;
} else {
groupedData[objIndex][element.Age]++;
}
});
return groupedData;
}
If you also want to sort by date, you could check out this post.
Hope it helped you!

Give this a try.
let data = [
{ Age: "(60-100)", Date: "28/05/20" },
{ Age: "(60-100)", Date: "28/05/20" },
{ Age: "(4-6)", Date: "28/05/20" },
{ Age: "(60-100)", Date: "29/05/20" },
{ Age: "(38-43)", Date: "29/05/20" },
{ Age: "(4-6)", Date: "29/05/20" },
{ Age: "(38-43)", Date: "30/05/20" },
{ Age: "(38-43)", Date: "30/05/20" }
];
let res = [];
data.map((d, index) => {
if (!res.some(val => val.Date === d.Date)) {
d[`${d.Age}`] = 1
res.push(d)
delete(d.Age)
} else {
let index = res.findIndex(val => val.Date == d.Date);
let _d = res[index];
if (_d.hasOwnProperty(`${d.Age}`)) {
_d[`${d.Age}`] = parseInt(_d[`${d.Age}`] + 1)
} else {
_d[`${d.Age}`] = 1
}
res[index] = _d;
}
})
console.log(res)

try this:
var result={};
for(var item of data) {
if(result[item.Date]==undefined) result[item.Date]={};
if(result[item.Date][item.Age]==undefined) result[item.Date][item.Age]=0;
result[item.Date][item.Age]++;
}
This gives you an object (not an array) with keys of Date and values as object with keys of Age and values as count.
If you still need an array, you can iterate over the result and construct an array.
result=={
"28/05/20": {
"(60-100)": 2,
"(4-6)": 1
},
"29/05/20": {
"(60-100)": 1,
"(38-43)": 1,
"(4-6)": 1
},
"30/05/20": {
"(38-43)": 2
}
}
If you want the array, you can create resultArr=[], iterate over keys of result, tempObj, add key "Date" and value of iterated key, then iterate over keys of iterated key, add each "Age" with it's count, then push tempObj into resultArr...

Condensed version based on #Dante Culaciati approach with optional sort parameter.
const condenseAge = (arr, isSort = true) => {
let r = [];
arr.map((val) => {
let i = r.findIndex(obj => obj.Date == val.Date);
(i < 0) && r.unshift({Date: val.Date}) && (i = 0);
(!r[i][val.Age]) ? r[i][val.Age] = 1 : r[i][val.Age]++;
});
return !isSort?r:r.sort((a,b)=>(ac=a['Date'].split('/'), bc=b['Date'].split('/'), new Date(ac[2],ac[1],ac[0]) - new Date(bc[2],bc[1],bc[0])));
}
console.log(condenseAge([
{ Age: "(4-6)", Date: "02/06/20"},
{ Age: "(60-100)", Date: "28/05/20" },
{ Age: "(60-100)", Date: "28/05/20" },
{ Age: "(4-6)", Date: "28/05/20" },
{ Age: "(60-100)", Date: "29/05/20" },
{ Age: "(38-43)", Date: "29/05/20" },
{ Age: "(4-6)", Date: "29/05/20" },
{ Age: "(38-43)", Date: "30/05/20" },
{ Age: "(38-43)", Date: "30/05/20" }
]));

Related

Find the difference between two complex objects containing array of objects

let baseObj = {
place: {city: 'Bangalore', pin: 123456},
office: [
{ name: 'Tom', age: 22, salutation: { title: 'Mr'}},
{ name: 'John', age: 31, salutation: { title: 'Mr'}}
]
}
let updatedObj = {
place: {city: 'Bangalore', pin: 99999},
office: [
{ name: 'Tom', age: 22, salutation: { title: 'Mr'}},
{ name: 'Peter', age: 16, salutation: { title: 'Mr'}},
{ name: 'John', age: 31, salutation: { title: 'Mr'}}
]
}
expected result = {
place: {city: 'Bangalore', pin: 99999},
office: [
{ name: 'Peter', age: 16, salutation: { title: 'Mr'}}
]
}
Note: comparison can be done by finding the properties of object and values but no comparison should be done hardcoding the properties
tried comparing the object but when we have an array of object i.e office, comparing with index(i.e 0,1) doesn't help as the array might not be sorted so couldn't proceed much
have tried the below code but it fails to get the desired output if the objects in an array are in different sequence as compared to the other array
ex. office1: [
{ name: 'Tom', age: 22, salutation: { title: 'Mr'}},
{ name: 'John', age: 31, salutation: { title: 'Mr'}}
]
office2: [
{ name: 'Tom', age: 22, salutation: { title: 'Mr'}},
{ name: 'Peter', age: 16, salutation: { title: 'Mr'}},
{ name: 'John', age: 31, salutation: { title: 'Mr'}}
]
function findDiff(obj1, obj2) {
var diffObj = Array.isArray(obj2) ? [] : {}
Object.getOwnPropertyNames(obj2).forEach(function(prop) {
if(prop !=='lenght' ){
if (typeof obj2[prop] === 'object') {
diffObj[prop] = obj1[prop]== undefined? obj2[prop]: findDiff(obj1[prop], obj2[prop])
if (Array.isArray(diffObj[prop]) && Object.getOwnPropertyNames(diffObj[prop]).length === 1 || Object.getOwnPropertyNames(diffObj[prop]).length === 0) {
delete diffObj[prop]
}
}} else if(prop !=='lenght') {
if(obj1[prop] !== obj2[prop]){
diffObj[prop] = obj2[prop]
}
}
});
return diffObj
}
This compare function seems to achieve exactly what you want :
const baseObj = {"grade":"A","queue":"1","myCollections":{"myCollection":[{"commonCollection":[{"winterCollection":[{"name":"ICE","isChilled":"true"}]}]}]},"remarks":{"remark":[{"name":"GOOD","category":"A","text":{"value":"Very Good"},"indicator":"good"}]}}
const updatedObj = {"grade":"A","queue":"1","myCollections":{"myCollection":[{"commonCollection":[{"winterCollection":[{"name":"ICE","isChilled":"true"},{"code":"SNOW","isChilled":"true"}]}]}]},"remarks":{"remark":[{"name":"GOOD","category":"A","text":{"value":"Very Good"},"indicator":"good"},{"name":"BEST","text":{"value":"Test"},"category":"O","indicator":"outstanding"}]}}
const compare = (a, b, allObj = true) => {
if (typeof a !== 'object') return a === b ? null : b
if (Array.isArray(a)) {
const arr = []
b.forEach(e => {
if (a.every(el => compare(el, e, true) !== null))
arr.push(e)
});
return arr.length === 0 ? null : arr
} else {
const keys = Object.keys(b) // assuming a and b have the same properties
const obj = allObj ? b : {}
let changed = false
keys.map(key => {
const compared = compare(a[key], b[key], true)
if (compared) {
obj[key] = compared
changed = true
}
})
return changed ? obj : null
}
}
const expectedResult = {"grade":"A","queue":"1","myCollections":{"myCollection":[{"commonCollection":[{"winterCollection":[{"code":"SNOW","isChilled":"true"}]}]}]},"remarks":{"remark":[{"name":"BEST","text":{"value":"Test"},"category":"O","indicator":"outstanding"}]}}
const result = compare(baseObj, updatedObj)
console.log(result)
console.log(expectedResult)
console.log(JSON.stringify(result) === JSON.stringify(expectedResult))
PS: I compared each pair but it is O(n^2). The best way is if you had an id property on every of array children.

How to loop through an object and then use array methods on its keys?

I see that all the loops for objects returns the key as string and the value, but I want to operate on the keys of the object itself. If I have this object:
const data = {
person1: [
{ id: 1, name: Mike, age: 24 },
{ id: 2, name: Bob, age: 31 }
],
person2: [
{ id: 3, name: Christin, age: 21 },
{ id: 4, name: Michelle, age: 33 }
],
}
const removePersonById = (id) => {
// Check which person the id belongs to and remove that person
const persons = Object.keys(data).map(person => ...)
}
I wanted to loop through data and run .includes on each person in order to remove them by the id, but I am at a loss on how to do that.
You can loop through all keys and delete that the person you want by id using the filter() method
const removePersonById = (id) => {
var all = Object.keys(data);
for(let person of all){
data[person] = data[person].filter(a => a.id!=id);
}
}
You could get the values and find the index. Then splice.
const
removePersonById = id => {
Object.values(data).forEach(a => {
const index = a.findIndex(o => o.id === id);
if (index !== 0) a.splice(index, 1);
});
};
You could use .some()
const data = {
person1: [
{ id: 1, name: "Mike", age: 24 },
{ id: 2, name: "Bob", age: 31 }
],
person2: [
{ id: 3, name: "Christin", age: 21 },
{ id: 4, name: "Michelle", age: 33 }
],
}
const removePersonById = (id) => {
// Check which person the id belongs to and remove that person
Object.keys(data).map(person => {
if (data[person].some(p => p.id === id)) delete data[person];
})
}
removePersonById(3)
console.log(data)
Use Object.entries() so you can iterate over the keys and values together. Then you can test the value to see if the id is found.
Then use the delete operator to remove that key from the object.
const removePersonById = id => {
delete data[id];
};
const data = {
person1: [
{ id: 1, name: "Mike", age: 24 },
{ id: 2, name: "Bob", age: 31 }
],
person2: [
{ id: 3, name: "Christin", age: 21 },
{ id: 4, name: "Michelle", age: 33 }
],
};
const removePersonById = (id) =>
Object.entries(data).forEach(([key, value]) => {
if (value.some(({id: personid}) => personid == id)) {
delete data[key];
}
});
removePersonById(3);
console.log(data);
let data = {
person1: [
{ id: 1, name: "Mike", age: 24 },
{ id: 2, name: "Bob", age: 31 }
],
person2: [
{ id: 3, name: "Christin", age: 21 },
{ id: 4, name: "Michelle", age: 33 }
],
}
const removePersonById = (id) => {
// Check which person the id belongs to and remove that person
data = Object.keys(data).reduce((acc,key) => {
if(data[key].some(person=>person.id===id)) return acc
acc[key]= data[key]
return acc
}, {})
console.log(`Remove person with ID ${id}: `,data)
}
removePersonById(1)

group result using date from object keys and only get count the results

Hello I'm having a hard time getting this complex return using MongoDB nor Javascript. Hope can anyone teach me how to get this return.
Admin.
group result by id
user
flatten result
Here's the data example.
let user = [
{
_id: 123,
name: 'John',
createdAt: "2015-08-12T00:00:00Z"
},
{
_id: 124,
name: 'Jane',
createdAt: "2015-09-12T00:00:00Z"
},
{
_id: 125,
name: 'Robert',
createdAt: "2015-09-12T00:00:00Z"
},
{
_id: 126,
name: 'Samson',
createdAt: "2016-11-12T00:00:00Z"
}
]
Expected Result
user
[
{
"15-8": 1 //yyyy-mm: number of data for the month of august
},
{
"15-9": 2
},
{
"16-11": 1
}
]
admin
[
{
"15-8":
{
_id: 123,
count: 1
}
},
{
"15-9": {
_id: 124,
count: 1,
},{
_id: 125,
count: 1
},
{
"16-11": {
_id: 126,
count: 1
}
}
]
You should have the function to get key from date string named getKeyFromDate with format result YY-MM
Loop user data to aggregate your data by using reduce, for example.
let user = [
{
_id: 123,
name: 'John',
createdAt: "2015-08-12T00:00:00Z"
},
{
_id: 124,
name: 'Jane',
createdAt: "2015-09-12T00:00:00Z"
},
{
_id: 125,
name: 'Robert',
createdAt: "2015-09-12T00:00:00Z"
},
{
_id: 126,
name: 'Samson',
createdAt: "2016-11-12T00:00:00Z"
}
];
const getKeyFromDate = (dateString) => {
var date = new Date(dateString);
var year = date.getFullYear().toString().substr(2, 3);
var month = date.getMonth() + 1;
return `${year}-${month}`; // YY-MM
};
var result = user.reduce((acc, {createdAt}) => {
var key = getKeyFromDate(createdAt);
acc[key] = acc[key] || {[key]: 0}; //Also use shortcut like: acc[key] ??= {[key]: 0};
acc[key][key] += 1;
return acc;
}, {});
console.log(Object.values(result));
You can also use for..of if you're not familiar with .reduce
var result2 = {};
for(let {createdAt} of user){
var key = getKeyFromDate(createdAt);
result2[key] = result2[key] || {[key]: 0};
result2[key][key] += 1;
}
console.log(Object.values(result2));

How can I minimize a code function that finds repeated values in an array of objects in JavaScript?

I need to fix this function, which must find two similar names in an array of objects.
I tried to do this, and it's working, but the test tells me that it should be just only one loop and one if
function searchByName() {
const values = [
{ name: 'Johny Walker', birthDate: '1995-12-17' },
{ name: 'Andrew', birthDate: '2001-10-29' },
{ name: 'Viktor', birthDate: '1998-11-09' },
{ name: 'Andrew', birthDate: '2011-05-09' }
];
for (let obj of values) {
for (let elem of values) {
if (obj == elem)
continue;
if (elem.name === obj.name && elem.age === obj.age) {
console.log(obj);
break;
}
}
}
};
Here is the example that must come out:
[
{ name: 'Andrew', birthDate: '2001-10-29' },
{ name: 'Andrew', birthDate: '2011-05-09' }
]
Just push names to the array and stop when there is a duplicate:
let hasDuplicates = [];
values.forEach((e, idx) => {
if(!hasDuplicates.includes(e.name))
if(idx !== values.length-1) { hasDuplicates.push(e.name); }
else { hasDuplicates = false; }
else { hasDuplicates = e; }
});
And then you can use that variable:
if(hasDuplicates) {...}
You can find the duplication count by name key using Array.reduce function.
And from the duplication result, you can filter the duplicated ones only and show them using Array.filter & Array.map.
const values = [
{ name: 'Johny Walker', birthDate: '1995-12-17' },
{ name: 'Andrew', birthDate: '2001-10-29' },
{ name: 'Viktor', birthDate: '1998-11-09' },
{ name: 'Andrew', birthDate: '2011-05-09' }
];
let duplicates = values.reduce((acc, cur) => {
if (acc[cur.name]) {
acc[cur.name].push(cur.birthDate);
} else {
acc[cur.name] = [ cur.birthDate ];
}
return acc;
}, {});
duplicates = Object.entries(duplicates).filter(([name, birth]) => birth.length > 1).map(([name, birth]) => {
return birth.map((item) => ({
name,
birthDate: item
}));
});
console.log(duplicates);
You can use the reduce method to iterate over the array and push items into the array. Then we just filter the array by its length. So if the length is greater than 1, it means we have found a duplicate:
const result = values.reduce((a, c)=> {
a[c.name] = a[c.name] || {...c, items: []} ;
a[c.name].items.push(c);
return a;
}, { });
let result = Object.values(result).filter(f => f.items.length > 1).flatMap(s => s.items);
An example:
const values = [
{ name: 'Johny Walker', birthDate: '1995-12-17' },
{ name: 'Andrew', birthDate: '2001-10-29' },
{ name: 'Viktor', birthDate: '1998-11-09' },
{ name: 'Andrew', birthDate: '2011-05-09' }
];
const result = values.reduce((a, c)=> {
a[c.name] = a[c.name] || {...c, items: []} ;
a[c.name].items.push(c);
return a;
}, { });
console.log(Object.values(result).filter(f => f.items.length > 1).flatMap(s => s.items));

How to find the value inside an array with objects with the most occuring value (deep mode)?

Let's say I have an array with objects like this:
const persons = [
{
name: "Erik",
age: 45
},
{
name: "Bob",
age: 37
},
{
name: "Erik",
age: 28
},
{
name: "Jasper",
age: 29
},
{
name: "Erik",
age: 34
}
];
How do I find the value based on a key with the most occuring value?
In this example, when passing name as key that would be Erik.
Something like this:
const deepMode = (array, key) => {
// Perhaps something with .reduce?
}
And when called, it should return:
deepMode(persons, "name"); // Returns "Erik"
You could take a Map, count the ocurrences and reduce the key/value pairs for getting the max valaue. Return the key without iterating again.
const
deepMode = (array, key) => Array
.from(array.reduce((m, o) => m.set(o[key], (m.get(o[key]) || 0) + 1), new Map))
.reduce((a, b) => a[1] > b[1] ? a : b)[0],
persons = [{ name: "Erik", age: 45 }, { name: "Bob", age: 37 }, { name: "Erik", age: 28 }, { name: "Jasper", age: 29 }, { name: "Erik", age: 34 }];
console.log(deepMode(persons, 'name'));
you can count keys by adding them in object and checking if key exists in object,then increment value, if not then add key into object, after that with Object.keys get keys of object sort them and get first element which is most occurring
const persons = [
{
name: "Erik",
age: 45
},
{
name: "Bob",
age: 37
},
{
name: "Erik",
age: 28
},
{
name: "Jasper",
age: 29
},
{
name: "Erik",
age: 34
}
];
const deepMode = (array, key) => {
const obj = {};
array.forEach(v => {
if (obj[v[key]]) {
obj[v[key]] += 1;
} else {
obj[v[key]] = 1;
}
});
return Object.keys(obj).sort((a,b) => obj[b]-obj[a])[0];
}
console.log(deepMode(persons, 'name'));
You could reduce into a Map, find the max, then find and return it.
function findMostOccuringKeyValue(arr, key) {
const grouped = arr.reduce((a, b) => a.set(b[key], (a.get(b[key]) || 0) + 1), new Map);
const max = Math.max(...grouped.values());
return [...grouped].find(([k, v]) => v === max)[0];
}
console.log(findMostOccuringKeyValue(persons, 'name'));
<script>
const persons = [
{
name: "Erik",
age: 45
},
{
name: "Bob",
age: 37
},
{
name: "Erik",
age: 28
},
{
name: "Jasper",
age: 29
},
{
name: "Erik",
age: 34
}
];
</script>

Categories

Resources