Group array of objects by common properties [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I want to get the count for only existing week.I want to get the calculation for month wise with week specific.
Now I can get the weekly count of each month.Now I want to display the week only for existing week.Now showing 0.for eg;may have value for week1 and week 2 I want to display only week1 and week 2 count in response for the month may.for july need to display week1 and week3
const response=[
{
"UserName": "User1",
"week": "Week 1",
"Type": "type3",
"months": "May",
"count": 2
},
{
"UserName": "User1",
"week": "Week 2",
"Type": "type1",
"months": "Jun",
"count": 1
},
{
"UserName": "User1",
"week": "Week 1",
"Type": "type2",
"months": "Jun",
"count": 1
},
{
"UserName": "User1",
"week": "Week 2",
"Type": "type1",
"months": "May",
"count": 1
},
{
"UserName": "User1",
"week": "Week 3",
"Type": "type2",
"months": "July",
"count": 1
},
{
"UserName": "User2",
"week": "Week 1",
"Type": "type3",
"months": "May",
"count": 2
},
{
"UserName": "User2",
"week": "Week 2",
"Type": "type1",
"months": "Jun",
"count": 1
},
{
"UserName": "User2",
"week": "Week 1",
"Type": "type2",
"months": "Jun",
"count": 1
},
{
"UserName": "User2",
"week": "Week 2",
"Type": "type1",
"months": "May",
"count": 1
},
{
"UserName": "User2",
"week": "Week 1",
"Type": "type2",
"months": "July",
"count": 1
}
];
const WEEKS = ["Week 1", "Week 2", "Week 3", "Week 4"];
const result = response.reduce((acc, obj) => {
existingObj = acc.find(ele => ele.UserName == obj.UserName && ele.month == obj.months && ele.Type == obj.Type)
if (existingObj) {
existingObj.Week1 += WEEKS.indexOf(obj.week) == 0 ? obj.count : 0;
existingObj.Week2 += WEEKS.indexOf(obj.week) == 1 ? obj.count : 0;
existingObj.Week3 += WEEKS.indexOf(obj.week) == 2 ? obj.count : 0;
existingObj.Week4 += WEEKS.indexOf(obj.week) == 3 ? obj.count : 0;
} else {
acc.push({
UserName: obj.UserName,
month: obj.months,
Type: obj.Type,
Week1: WEEKS.indexOf(obj.week) == 0 ? obj.count : 0,
Week2: WEEKS.indexOf(obj.week) == 1 ? obj.count : 0,
Week3: WEEKS.indexOf(obj.week) == 2 ? obj.count : 0,
Week4: WEEKS.indexOf(obj.week) == 3 ? obj.count : 0,
});
}
return acc;
}, []);
console.log(result);
expected as
[{"UserName":"user1","month":"May","Type":"Type3","Week1":2,"Week3":3},
{"UserName":"user2","month":"May","Type":"Type3","Week1":2},
{"UserName":"user1","month":"May","Type":"Type1","Week2":1},
{"UserName":"user2","month":"May","Type":"Type1","Week2":1,},
{"UserName":"user1","month":"Jun","Type":"Type1","Week2":1},
{"UserName":"user2","month":"Jun","Type":"Type1","Week2":1},
{"UserName":"user1","month":"Jun","Type":"Type2","Week1":1},
{"UserName":"user2","month":"Jun","Type":"Type2","Week1":1},
{"UserName":"user1","month":"Jul","Type":"Type2","Week3":1},
{"UserName":"user1","month":"Jul","Type":"Type2","Week1":1},
]

If the point was to regroup records in source array by UserName and month properties, you may build up the Map (using Array.prototype.reduce()) with composite key (comprised by UserName and month) and the value of corresponding groupped object, then extract those objects into array with Map.prototype.values():
const src = [{"UserName":"User1","week":"Week 1","Type":"type3","months":"May","count":2},{"UserName":"User1","week":"Week 2","Type":"type1","months":"Jun","count":1},{"UserName":"User1","week":"Week 1","Type":"type2","months":"Jun","count":1},{"UserName":"User1","week":"Week 2","Type":"type1","months":"May","count":1},{"UserName":"User1","week":"Week 3","Type":"type2","months":"July","count":1},{"UserName":"User2","week":"Week 1","Type":"type3","months":"May","count":2},{"UserName":"User2","week":"Week 2","Type":"type1","months":"Jun","count":1},{"UserName":"User2","week":"Week 1","Type":"type2","months":"Jun","count":1},{"UserName":"User2","week":"Week 2","Type":"type1","months":"May","count":1},{"UserName":"User2","week":"Week 1","Type":"type2","months":"July","count":1}],
result = [...src
.reduce((r, {UserName, week: w, Type, months, count}) => {
const key = UserName+"\ud8ff"+months,
week = w.replace(' ', ''),
grouppedRecord = r.get(key)
grouppedRecord ?
Object.assign(grouppedRecord, {[week]: count}) :
r.set(key, {UserName, Type, month: months, [week]: count})
return r
}, new Map)
.values()
]
console.log(result)
.as-console-wrapper{min-height:100%;}

You can first filter down for what ever you want and then loop through the whole thing with the filtered as lookup key.
Like filtering all weeks in May. Then use that for further work.
var existingWeeks = response.filter(function(obj) {
return (obj.months === "May") && (obj.User === "User1");
});

Related

Create new array with new keys and nested object from single array

I'm trying to organise data from an api that returns the following json:
[
{
"0": "THURSDAY 25th MARCH",
"1": "",
"2": ""
},
{
"0": "Snow Patrol",
"1": "Press Conference",
"2": "16:00 - 19:35"
},
{
"0": "",
"1": "",
"2": ""
},
{
"0": "FRIDAY 26th MARCH",
"1": "",
"2": ""
},
{
"0": "Arctic Moneys",
"1": "Concert",
"2": "11:55 - 12:40"
},
{
"0": "Rush",
"1": "Practice Session",
"2": "13:05 - 13:50"
}
]
The api returns an array with only numbers as keys and the next date starts after and empty object.
Into an organised array like so:
[
{
"date": "THURSDAY 25th MARCH",
"events": [
{
"band": "Snow Patrol",
"type": "Press Conference",
"time": "16:00 - 19:35"
}
]
},
{
"date": "FRIDAY 26th MARCH",
"events": [
{
"band": "Arctic Moneys",
"type": "Concert",
"time": "11:55 - 12:40"
},
{
"band": "Rush",
"type": "Practice Session",
"time": "13:05 - 13:50"
}
]
}
]
Any help would be much appreciated!
Cheers!
You could create an array of each object and check if all vlaues are empty strings or the last two ones.
The continue or build a new date object and add later all events to the last object.
const
data = [{ 0: "THURSDAY 25th MARCH", 1: "", 2: "" }, { 0: "Snow Patrol", 1: "Press Conference", 2: "16:00 - 19:35" }, { 0: "", 1: "", 2: "" }, { 0: "FRIDAY 26th MARCH", 1: "", 2: "" }, { 0: "Arctic Moneys", 1: "Concert", 2: "11:55 - 12:40" }, { 0: "Rush", 1: "Practice Session", 2: "13:05 - 13:50" }],
result = data.reduce((r, o) => {
const a = Object.assign([], o);
if (!a.join('')) return r;
if (!a.slice(1).join('')) {
r.push({ date: a[0], events: [] });
} else {
const [band, type, time] = a;
r[r.length - 1].events.push({ band, type, time });
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Merging multiple JSON objects from an array together [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have an array of JSON objects and I want to merge the objects that have the same text together while finding the average of relevance and the sum of count across all of the same instances.
var keywords = [
{
"text": "service businesses",
"relevance": 0.626303,
"count": 1
},
{
"text": "service businesses",
"relevance": 0.87319,
"count": 5
},
{
"text": "service businesses",
"relevance": 0.05,
"count": 100
},
{
"text": "restaurants",
"relevance": 0.614567,
"count": 16
},
{
"text": "restaurants",
"relevance": 0.609875,
"count": 4
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
},
I tried the solution posted here but, I am getting an output like this:
{
text: 'service businesses',
count: '[object Object][object Object]'
}
The output I am hoping for would look like this:
{
"text": "service businesses",
"relevance": 0.516497667,
"count": 106
},
{
"text": "restaurants",
"relevance": 0.612221,
"count": 20
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
},
Any help is much appreciated!
Using Array.prototype.reduce, you can group the elements by the text and based on that group data, can get the output as follows.
var keywords = [{
"text": "service businesses",
"relevance": 0.626303,
"count": 1
},
{
"text": "service businesses",
"relevance": 0.87319,
"count": 5
},
{
"text": "service businesses",
"relevance": 0.05,
"count": 100
},
{
"text": "restaurants",
"relevance": 0.614567,
"count": 16
},
{
"text": "restaurants",
"relevance": 0.609875,
"count": 4
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
}
];
const groupBy = keywords.reduce((acc, cur) => {
acc[cur.text] ? acc[cur.text] = {
...acc[cur.text],
count: acc[cur.text].count + cur.count,
relevance: [...acc[cur.text].relevance, cur.relevance]
} : acc[cur.text] = {
...cur,
relevance: [cur.relevance]
};
return acc;
}, {});
const output = Object.values(groupBy).map((item) => ({
...item,
relevance: item.relevance.reduce((acc, cur) => acc + cur, 0) / item.relevance.length
}));
console.log(output);
I ran it in two for loops and then calculated the relevance on the second loop.
I just kept track of the values in a normal object.
var keywords = [
{
"text": "service businesses",
"relevance": 0.626303,
"count": 1
},
{
"text": "service businesses",
"relevance": 0.87319,
"count": 5
},
{
"text": "service businesses",
"relevance": 0.05,
"count": 100
},
{
"text": "restaurants",
"relevance": 0.614567,
"count": 16
},
{
"text": "restaurants",
"relevance": 0.609875,
"count": 4
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
}
]
const objectMerge = (arr) => {
let map = {};
for(let idx in arr){
const { text, relevance, count } = arr[idx];
if(!map[text]){
map[text] = {
count: 0,
relevance: []
}
}
map[text].count += count
map[text].relevance.push(relevance)
}
for(const key in map){
let lenOfRelevance = map[key].relevance.length
map[key].relevance = map[key].relevance.reduce((a,b) => a+b) / lenOfRelevance
}
return map
}
console.log(objectMerge(keywords))

How to return and get the sum of object properties based on given filters?

I have the following object.
var data = [
{"Name":"ABC","Dept":"First","FY":"2016","Quarter":"1","Month":"April","Total":"100"},
{"Name":"ABC","Dept":"Second","FY":"2017","Quarter":"2","Month":"May","Total":"200"},
{"Name":"ABC","Dept":"First","FY":"2016","Quarter":"1","Month":"June","Total":"150"},
{"Name":"DEF","Dept":"First","FY":"2016","Quarter":"1","Month":"April","Total":"200"},
{"Name":"DEF","Dept":"Second","FY":"2017","Quarter":"2","Month":"May","Total":"100"},
{"Name":"DEF","Dept":"First","FY":"2016","Quarter":"1","Month":"June","Total":"500"}
]
I want to filter on the abve object to get:
a. I want to return Total based on my filters(ex: If I give Name as ABC, Dept as First, FY as 2016, Quarter as 1, Month as April, then it should filter/return the Total i.e 100 for the given filters)
b. Similarly, I want to return Sum of all the Totals(ex: if I give Name as ABC, Dept as First, FY as 2016 - then it should return sum of the required Total values(i.e 100+150=250) for the given FY 2016 only)
Please help me in this requirement, how can I achieve, Thanks.
I have tried below, but it is giving all the results for given Name(ex: If I give Name as ABC, then it is returning all the details ABC only)
return getData().then(res => {
res.data.filter(customerDetails =>{
if(customerDetails.Name === name && customerDetails.FY === fy && customerDetails.Quarter === quarter && customerDetails.Month === month && customerDetails.Dept === dept)
agent.add(`Details: ${name}, Dept: ${customerDetails.Dept},
FY: ${customerDetails.FY}, Quarter: ${customerDetails.Quarter}, Month: ${customerDetails.Month},
Total: ${customerDetails.Total} `);
});
});
You can use Array.filter() to do that. Filter data based on passed values, and then add Total values of filtered data to get final total.
var data = [{ "Name": "ABC", "Dept": "First", "FY": "2016", "Quarter": "1", "Month": "April", "Total": "100" }, { "Name": "ABC", "Dept": "Second", "FY": "2017", "Quarter": "2", "Month": "May", "Total": "200" }, { "Name": "ABC", "Dept": "First", "FY": "2016", "Quarter": "1", "Month": "June", "Total": "150" }, { "Name": "DEF", "Dept": "First", "FY": "2016", "Quarter": "1", "Month": "April", "Total": "200" }, { "Name": "DEF", "Dept": "Second", "FY": "2017", "Quarter": "2", "Month": "May", "Total": "100" }, { "Name": "DEF", "Dept": "First", "FY": "2016", "Quarter": "1", "Month": "June", "Total": "500" }];
function getTotal(filters) {
var total = 0;
const filteredData = data.filter(item => {
for (var key in filters) {
if (item[key] != filters[key]) {
return false;
}
}
return true;
});
filteredData.forEach(value => total += Number(value.Total));
return total;
}
console.log(getTotal({ "Name": "ABC", "Dept": "First", "FY": "2016" }));
console.log(getTotal({"Name": "DEF" }));
You could take an object with the wanted filter values and filter the array and return the sum of all Total.
function getTotal(data, filters) {
var f = Object.entries(filters);
return data
.filter(o => f.every(([k, v]) => o[k] == v))
.reduce((s, { Total }) => s + +Total, 0);
}
var data = [{ Name: "ABC", Dept: "First", FY: "2016", Quarter: "1", Month: "April", Total: "100" }, { Name: "ABC", Dept: "Second", FY: "2017", Quarter: "2", Month: "May", Total: "200" }, { Name: "ABC", Dept: "First", FY: "2016", Quarter: "1", Month: "June", Total: "150" }, { Name: "DEF", Dept: "First", FY: "2016", Quarter: "1", Month: "April", Total: "200" }, { Name: "DEF", Dept: "Second", FY: "2017", Quarter: "2", Month: "May", Total: "100" }, { Name: "DEF", Dept: "First", FY: "2016", Quarter: "1", Month: "June", Total: "500" }];
console.log(getTotal(data, { Name: 'ABC', Dept: 'First', FY: 2016, Quarter: 1, Month: 'April' })); // 100
console.log(getTotal(data, { Name: 'ABC', Dept: 'First', FY: 2016 })); // 100 + 150 = 250

Javascript get value in json based on another value

I have a json similar to this one
{
"id": "1",
"month": "January",
"type": "inc",
"Value": "780.00",
"year": "2018",
},
{
"id": "2",
"month": "January",
"type": "inc",
"Value": "80.00",
"year": "2018",
},
{
"id": "3",
"month": "February",
"type": "inc",
"Value": "100.00",
"year": "2018",
},...
Now I need to get all the Value from the object for all the months, as you can see I may have more objects with the same month name. The closer I got to was creating 2 arrays 1 with the list of Months and 1 with the value but I got stuck, can someone lead me to the correct path?
The desired output would be to get an array like that ["January"=>1500, "February"=>2000...] or have 2 arrays, 1 with the list of months where there is income (I already have it) and the second the total income for these months, so it's like this: ["January", "February", "March"..] and the second one [1500, 2000, 300...]
You can use the function Array.prototype.reduce to sum each Value by month.
let arr = [{ "id": "1", "month": "January", "type": "inc", "Value": "780.00", "year": "2018", }, { "id": "2", "month": "January", "type": "inc", "Value": "80.00", "year": "2018", }, { "id": "3", "month": "February", "type": "inc", "Value": "100.00", "year": "2018", }],
result = arr.reduce((a, {month, Value}) => {
a[month] = (a[month] || 0) + +Value;
return a;
}, Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I actually can barely understand what you would like to achieve. Please provide some example.
If I understood you correctly, you can use map function of js array to map each object to its Value.
let arr = [...];
console.log(arr.map(item => item.Value));
You can do
var fabuaryDate = yourdata
.filter(function(data) { return data.month == "February" })
.map(function(x){return {value: x.Value} })
To get result in following format :
{
jan : [1,2,3],
feb : [3,4,5,6],
april : [3,4,5]
}
do this :
var output = {}
arr.forEach(element => {
if(!output[element.month]){
output[month] = new Array();
}
output[month].push(element.value);
});
You can iterate the object and fill an array with the values of the field you want to extract, like so:
const data = [ {
"id": "1",
"month": "January",
"type": "inc",
"Value": 780.00,
"year": "2018",
},
{
"id": "2",
"month": "January",
"type": "inc",
"Value": 80.00,
"year": "2018",
},
{
"id": "3",
"month": "February",
"type": "inc",
"Value": 100.00,
"year": "2018",
}];
let dataArray = data.reduce((accum, d) => {
if(!accum[d.month]) accum[d.month] = 0;
accum[d.month] += d.Value;
return accum;
},{});
console.log(dataArray);
Although you don't seem to be clear enough with what have you tried here is an example of what you could do in order to read all the values inside the json.
function myFunction(item) {
console.log(item.month + " with the value " + item.Value)
}
var jsonArray = [{"id": "1","month": "January", "type": "inc", "Value": "780.00", "year": "2018" }, { "id": "2", "month": "January", "type": "inc", "Value": "80.00", "year": "2018" }, { "id": "3", "month": "February", "type": "inc", "Value": "100.00", "year": "2018" }];
jsonArray.forEach(myFunction);
Since you're working with an array of objects you must access to each of the objects in the array and then get the attribute that you require.
Hope this help, have a great day.

Converting an object to an array

I tried by using Object.keys() to convert the object
var obj1={
"jan": {
"COAL": "25"
},
"feb": {
"ROM": "50",
"WASTE": "55"
},
"april": {
"COAL": "60"
}
}
to
var obj2=[
{
"month": "jan",
"product": "COAL",
"quantity": "25"
},
{
"month": "feb",
"product": "ROM",
"quantity": "50"
},
{
"month": "feb",
"product": "WASTE",
"quantity": "55"
},
{
"month": "april",
"product": "COAL",
"quantity": "60"
}
]
but failed in the middle as I'm not able to calculate the properties say for example in "feb" there are two products "ROM" and "WASTE", but this can go upto 3 or 4. Can anyone please suggest possible solution for this problem?
This will do:
var res = []
for(i in obj1){
var rowObj = obj1[i];
for(j in rowObj){
var newObj = {'month' : i, 'product' : j, 'quantity' : rowObj[j]}
res.push(newObj);
}
}
console.log(res);
You need to loop over the keys in the outer object, then the keys in the inner objects, so as long as you can depend on ES5 Array methods:
var obj1={
"jan": {
"COAL": "25"
},
"feb": {
"ROM": "50",
"WASTE": "55"
},
"april": {
"COAL": "60"
}
}
var o = Object.keys(obj1).reduce(function(acc, month, i) {
Object.keys(obj1[month]).forEach(function(product) {
acc.push({'month':month, 'product':product, 'quantity':obj1[month][product]})
});
return acc;
}, []);
document.write(JSON.stringify(o));
Using ES6 arrow functions it becomes a little more concise:
var o = Object.keys(obj1).reduce((acc, m) => {
Object.keys(obj1[m]).forEach(p => acc.push({'month':m, 'product':p, 'quantity':obj1[m][p]}));
return acc;
}, []);

Categories

Resources