Related
This question already has answers here:
Replacing objects in array
(17 answers)
Closed 3 years ago.
I'm trying to get an array from two different arrays. I'm not sure how to do it with ES6.
I want the current_year_data is replacing to previous_year_data
The First array is:
let previous_year_data = [
{ month: "January", value: 300 },
{ month: "February", value: 1 },
{ month: "March", value: 2 },
{ month: "April", value: 3 },
{ month: "May", value: 4 },
{ month: "Jun", value: 5 },
{ month: "July", value: 6 },
{ month: "August", value: 7 },
{ month: "September", value: 8 },
{ month: "October", value: 9 },
{ month: "November", value: 10 },
{ month: "December", value: 11 },
];
Second array:
let current_year_data = [
{ month: "January", value: 4459 }
];
The result should be in:
let current_year_data = [
{ month: "January", value: 4459 },
{ month: "February", value: 1 },
{ month: "March", value: 2 },
{ month: "April", value: 3 },
{ month: "May", value: 4 },
{ month: "Jun", value: 5 },
{ month: "July", value: 6 },
{ month: "August", value: 7 },
{ month: "September", value: 8 },
{ month: "October", value: 9 },
{ month: "November", value: 10 },
{ month: "December", value: 11 },
];
Thanks
It is possible to use map method. In addition, you can use Map collection to have O(1) of access to elements items when you map your array:
let unique = new Map(current_year_data.map(s=> [s.month, s.value]))
previous_year_data.map(({month, value})=> ({month, value: unique.get(month) || value }));
An example:
let previous_year_data = [
{ month: "January", value: 300 },
{ month: "February", value: 1 },
{ month: "March", value: 2 },
{ month: "April", value: 3 },
{ month: "May", value: 4 },
{ month: "Jun", value: 5 },
{ month: "July", value: 6 },
{ month: "August", value: 7 },
{ month: "September", value: 8 },
{ month: "October", value: 9 },
{ month: "November", value: 10 },
{ month: "December", value: 11 },
];
let current_year_data = [
{ month: "January", value: 4459 }
];
let unique = new Map(current_year_data.map(s=> [s.month, s.value]))
const result = previous_year_data.map(({month, value})=>
({month, value: unique.get(month) || value }));
console.log(result)
For such requirements, combine or merge JSON arrays unique by the key will work! See the following:
// Note: this will pick the last duplicated item in the list.
const previous_year_data = [
{ month: "January", value: 300 },
{ month: "February", value: 1 },
{ month: "March", value: 2 },
{ month: "April", value: 3 },
{ month: "May", value: 4 },
{ month: "Jun", value: 5 },
{ month: "July", value: 6 },
{ month: "August", value: 7 },
{ month: "September", value: 8 },
{ month: "October", value: 9 },
{ month: "November", value: 10 },
{ month: "December", value: 11 },
];
const current_year_data = [
{ month: "January", value: 4459 }
];
const key = 'month'; //Replace this key with unique key
const result = [...new Map([...previous_year_data, ...current_year_data].map(item =>
[item[key], item])).values()];
console.log(result);
/*OUTPUT
[
{
"month": "January",
"value": 4459
},
{
"month": "February",
"value": 1
},
{
"month": "March",
"value": 2
},
{
"month": "April",
"value": 3
},
{
"month": "May",
"value": 4
},
{
"month": "Jun",
"value": 5
},
{
"month": "July",
"value": 6
},
{
"month": "August",
"value": 7
},
{
"month": "September",
"value": 8
},
{
"month": "October",
"value": 9
},
{
"month": "November",
"value": 10
},
{
"month": "December",
"value": 11
}
]
*/
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
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.
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 4 years ago.
Improve this question
I have the array as below,
let yearAndMonth = [
{ "year": 2013, "month": "FEBRUARY" },
{ "year": 2015, "month": "MARCH" },
{ "year": 2013, "month": "JANUARY" },
{ "year": 2015, "month": "FEBRUARY" }
]
I want to sort the array by year first and after that sort month from the year,
I want the output like this,
yearAndMonth = [
{ "year": 2013, "month": "JANUARY " },
{ "year": 2013, "month": "FEBRUARY" },
{ "year": 2015, "month": "FEBRUARY" },
{ "year": 2015, "month": "MARCH" }
]
How to achieve this?
You could take an object for the month names and their numerical value.
The chain the order by taking the delta of year and month.
var array = [{ year: 2013, month: "FEBRUARY" }, { year: 2015, month: "MARCH" }, { year: 2013, month: "JANUARY" }, { year: 2015, month: "FEBRUARY" }];
array.sort(function (a, b) {
var MONTH = { JANUARY: 0, FEBRUARY: 1, MARCH: 2, APRIL: 3, MAY: 4, JUNE: 5, JULY: 6, AUGUST: 7, SEPTEMBER: 8, OCTOBER: 9, NOVEMBER: 10, DECEMBER: 11 };
return a.year - b.year || MONTH[a.month] - MONTH[b.month];
});
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can create an array for months names and sort like this:
let data = [
{ "year": 2013, "month": "FEBRUARY" }, { "year": 2015, "month": "MARCH" },
{ "year": 2013, "month": "JANUARY" }, { "year": 2015, "month": "FEBRUARY" }
];
let months = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
"JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];
data.sort(
(a, b) => (a.year - b.year) || (months.indexOf(a.month) - months.indexOf(b.month))
);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can make a map which maps the Month to the month number and then use Arrays.sort() with your own custom comparator :
let months = { 'JANUARY' : 1, 'FEBRUARY' : 2, 'MARCH' : 3, 'APRIL' : 4, 'MAY' : 5, 'JUNE' : 6, 'JULY' : 7, 'AUGUST' : 8, 'SEPTEMBER' : 9, 'OCTOBER' : 10, 'NOVEMBER' : 11, 'DECEMBER' : 12 };
let yearAndMonth = [ { "year": 2013, "month": "FEBRUARY" }, { "year": 2015, "month": "MARCH" }, { "year": 2013, "month": "JANUARY" }, { "year": 2015, "month": "FEBRUARY" } ];
yearAndMonth.sort((a,b)=> a.year - b.year || months[a.month.toUpperCase()] - months[b.month.toUpperCase()]);
console.log(yearAndMonth);
Since you are ok with using lodash this can be achived by a simple sortBy
_.sortBy(yearAndMonth, a => new Date(1+ a.month + a.year))
It will construct a new Date for each month and year (with date 1) and that should work the way you want.
let yearAndMonth = [
{ "year": 2013, "month": "FEBRUARY" },
{ "year": 2015, "month": "MARCH" },
{ "year": 2013, "month": "JANUARY" },
{ "year": 2015, "month": "FEBRUARY" }
]
let res = _.sortBy(yearAndMonth, a => new Date(1 + a.month + a.year));
console.log('Sorted Result: ', res);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Note: You do not need to have array/object/map of all the months for this to have a look up to perform > or <
You can also use lodash library for sorting data by multiple column.
I have created a demo on Stackblitz. I hope this will help/guide to you/others.
lodash - Documentation
Component.html
<table width="100%">
<tr>
<td>Year</td>
<td>Month</td>
</tr>
<tr *ngFor="let datas of sortedData">
<td>{{datas.year}}</td>
<td>{{datas.month}}</td>
</tr>
</table>
Component.ts
sortedData: any[];
data = [
{ "year": 2013, "month": "FEBRUARY" },
{ "year": 2015, "month": "MARCH" },
{ "year": 2013, "month": "JANUARY" },
{ "year": 2013, "month": "MARCH" },
{ "year": 2013, "month": "APRIL" },
{ "year": 2015, "month": "FEBRUARY" }
];
monthArray: any = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
"JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];
ngOnInit() {
this.sortedData = _.orderBy(data, [(datas) => datas.year, (user) => (this.monthArray.indexOf(user.month))], ["asc", "asc"]);
console.log(this.sortedData);
}
Declaring the month names in an array to get the relative value of the month string when comparing with each other.
First comparison will be on the year, if both the year values are same then proceeding with the month comparison based on the months array created.
let months = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
"JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];
yearAndMonth.sort((a,b) =>{
if(a.year > b.year) return 1;
else if(a.year < b.year) return -1;
else {
if(months.indexOf(a.month.toUpperCase()) >
months.indexOf(b.month.toUpperCase()))
return 1;
else if(months.indexOf(a.month.toUpperCase()) <
months.indexOf(b.month.toUpperCase()))
return -1
else return 0;
}
});
See also: JsFiddle
Allow me to provide a plain ES version (sort array of objects on 1 or more key values, serial dependant (sort on 1, sort 2 within 1, sort on 3 within 1 and 2 etc.), non mutating, i.e. keep the original array as is):
const log = (...str) =>
document.querySelector("pre").textContent += `${str.join("\n")}\n`;
const data = getData();
const xSort = XSort();
const months = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
"JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ];
log( JSON.stringify(
xSort
.create(data)
.orderBy( {key: "year"}, { key: v => months.indexOf(v.month) } ),
null,
" ")
);
function XSort() {
const multiSorter = sortKeys => {
if (!sortKeys || sortKeys[0].constructor !== Object) {
throw new TypeError("Provide at least one {key: [keyname]} to sort on");
}
return function (val0, val1) {
for (let sortKey of sortKeys) {
const v0 = sortKey.key instanceof Function ? sortKey.key(val0) : val0[sortKey.key];
const v1 = sortKey.key instanceof Function ? sortKey.key(val1) : val1[sortKey.key];
const isString = v0.constructor === String || v1.constructor === String;
const compare = sortKey.descending ?
isString ? v1.toLowerCase().localeCompare(v0.toLowerCase()) : v1 - v0 :
isString ? v0.toLowerCase().localeCompare(v1.toLowerCase()) : v0 - v1;
if (compare !== 0) {
return compare;
}
}
};
}
const Sorter = function (array) {
this.array = array;
};
Sorter.prototype = {
orderBy: function(...sortOns) {
return this.array.slice().sort(multiSorter(sortOns));
},
};
return {
create: array => new Sorter(array)
};
}
function getData() {
return [{
"year": 2013,
"month": "FEBRUARY",
},
{
"year": 2015,
"month": "MARCH",
},
{
"year": 2015,
"month": "SEPTEMBER",
},
{
"year": 2013,
"month": "JANUARY",
},
{
"year": 2013,
"month": "MARCH",
},
{
"year": 2013,
"month": "APRIL",
},
{
"year": 2015,
"month": "FEBRUARY",
}
];
}
<pre></pre>
I am trying to create different dataset based on month value. For eg. for June month one dataset and for July another dataset. But in my code, all the month values are getting combined and created as one dataset.
It will be really helpful who can help me in creating different dataset dynamically. I have attached the fiddle which I tried with my data object
JSFIDDLE
var obj = [{
date: "2017-06-01",
reqC: "129963",
month: "JUNE",
resC: "80522"
}, {
date: "2017-06-05",
reqC: "261162",
month: "JUNE",
resC: "83743"
},{
date: "2017-07-03",
reqC: "438860",
month: "JULY",
resC: "166107"
}]
var maindataset = [];
var dataset = [];
["reqC", "resC"].forEach((series) => {
dataset.push({
seriesname: series,
data: obj.map((el) => {
return el[series]
})
})
});
maindataset.push({
dataset: dataset
});
alert(JSON.stringify(maindataset));
// Expected Output
{
"dataset": [
{
"dataset": [ //June
{
"seriesname": "Req",
"data": [
{
"value": "129963"
},
{
"value": "261162"
}
]
},
{
"seriesname": "Res",
"data": [
{
"value": "80522"
},
{
"value": "83743"
}
]
}
]
},
{
"dataset": [ //July
{
"seriesname": "Req",
"data": [
{
"value": "438860"
}
]
},
{
"seriesname": "Res",
"data": [
{
"value": "166107"
}
]
}
]
}
]
}
You could use a nested hash table and iterate later the keys for the wanted parts.
var data = [{ date: "2017-06-01", reqC: "129963", month: "JUNE", resC: "80522" }, { date: "2017-06-05", reqC: "261162", month: "JUNE", resC: "83743" }, { date: "2017-07-03", reqC: "438860", month: "JULY", resC: "166107" }],
result = { dataset: [] },
parts = { reqC: 'Req', resC: 'Res' },
hash = { _: result.dataset };
data.forEach(function (a) {
var temp = hash;
if (!temp[a.month]) {
temp[a.month] = { _: [] };
temp._.push({ dataset: temp[a.month]._ });
}
temp = temp[a.month];
Object.keys(parts).forEach(function (k) {
if (!temp[k]) {
temp[k] = { _: [] };
temp._.push({ seriesname: parts[k], data: temp[k]._ });
}
temp[k]._.push({ value: a[k] });
});
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can create groups based on month and then you can output the desired data structure. Check the snippet.
var obj = [{
date: "2017-06-01",
reqC: "129963",
month: "JUNE",
resC: "80522"
}, {
date: "2017-06-05",
reqC: "261162",
month: "JUNE",
resC: "83743"
},{
date: "2017-07-03",
reqC: "438860",
month: "JULY",
resC: "166107"
}];
var result = {};
var groups = obj.reduce(function(acc, obj) {
acc[obj.month] = acc[obj.month] || [];
acc[obj.month].push(obj);
return acc;
}, {});
//console.log(groups);
result.dataset = Object.keys(groups).map(function(key) {
return {
dataset: [{
"seriesname" : "Req",
"data": groups[key].map(function(o) {
return { value : o.reqC };
})
}, {
"seriesname" : "Res",
"data": groups[key].map(function(o) {
return { value : o.resC };
})
}]
};
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You cannot use the same property name for an object twice. You have an object in your data that looks like this:
"data": [
{
"value": "80522"
},
{
"value": "83743"
}
]
Either change the keys to unique ones:
"data": [
{
"value1": "80522"
},
{
"value2": "83743"
}
]
Or make it an array:
"data": [ "80522", "83743" ]
You need to add check for month as well.
Try this:
var obj = [{
date: "2017-06-01",
reqC: "129963",
month: "JUNE",
resC: "80522"
}, {
date: "2017-06-05",
reqC: "261162",
month: "JUNE",
resC: "83743"
},{
date: "2017-07-03",
reqC: "438860",
month: "JULY",
resC: "166107"
}]
var maindataset = [];
["JUNE","JULY"].forEach((month)=>{
var dataset = [];
["reqC", "resC"].forEach((series) => {
dataset.push({
seriesname: series,
data: obj.reduce((filtered, el) => {
if(el["month"] === month){
filtered.push({value: el[series]});
}
return filtered;
},[])
})
});
maindataset.push({
dataset: dataset
});
})
alert(JSON.stringify(maindataset));
output:
[{
"dataset": [{
"seriesname": "reqC",
"data": [{
"value": "129963"
}, {
"value": "261162"
}]
}, {
"seriesname": "resC",
"data": [{
"value": "80522"
}, {
"value": "83743"
}]
}]
}, {
"dataset": [{
"seriesname": "reqC",
"data": [{
"value": "438860"
}]
}, {
"seriesname": "resC",
"data": [{
"value": "166107"
}]
}]
}]