Get sum of array values based on date values of other array - javascript

So i have problem like this:
I have 2 arrays:
one from mysql query that contains date when order have been created and total sum of it
const ordersData = [
0: {id: 1, data: '2021-11-23T00:00:00.000Z', price: 394}
1: {id: 2, data: '2021-11-23T00:00:00.000Z', price: 315.3}
2: {id: 3, data: '2021-11-23T00:00:00.000Z', price: 16445}
...
6: {id: 7, data: '2021-11-23T00:00:00.000Z', price: 200}
7: {id: 8, data: '2021-12-22T00:00:00.000Z', price: 618}
]
second is array is where i have monthly sum, month, first and last day of month
const pastMonthsData = [
0: {
month: "december",
firstDay: Wed Dec 01 2021,
lastDay: Fri Dec 31 2021,
totalMonthSum: x
},
1: {
month: "november",
firstDay: Mon Nov 01 2021,
lastDay: Tue Nov 30 2021,
totalMonthSum: x
}
]
I need to check if date from order array is in between date of pastMonthsData and add price to totalMonthSum.
So far i created func like this but it only works for december, for november there is no result.
pastMonthsData.forEach((el, i) => {
el.totalMonthSum = ordersData.reduce((total, item) => {
let itemDate = new Date(item.data);
if(el.firstDay.getTime() < itemDate.getTime() && itemDate.getTime() < el.lastDay.getTime()) {
return total + item.price
} else {
return 0
}
})
});

Two fixes:
initialize the accumulated total to zero
return the accumulated total, rather than zero, when a date is not in range
For example:
pastMonthsData.forEach((el, i) => {
el.totalMonthSum = ordersData.reduce((total, item) => {
let itemDate = new Date(item.data);
if (el.firstDay.getTime() < itemDate.getTime() && itemDate.getTime() < el.lastDay.getTime()) {
return total + item.price;
} else {
return total;
}
}, 0)
});

Related

How to add the values ​in an array of objects depending on the date value of each object

I have this array:
[{start_date: "2022-12-05T04:00:00Z" ,distance: 1000, time: 3600}
,{start_date: "2022-02-07T04:00:00Z" ,distance: 1500, time: 6400},
{start_date: "2022-12-08T04:00:00Z" ,distance: 1000, time: 1300}]
I want to add the distance and time values ​​grouping them by the month indicated by the start_date value. For example, if two start_dates have the same month 2022-12-01 and 2022-12-08, how can I add the distance and time values ​​of those two months?
so i get a new array like this:
[{month: 12 ,total distance: 2000, total time: 4900},
{month: 02 , total distance: 1500, total time: 6400} ]
you can use reduce to group them by month which will give an object like
{
12: {
distance: 2000,
month: 12,
time: 4900
},
2: {
distance: 1500,
month: 2,
time: 6400
}
}
and using Object.values get the values array of it
let x = [{start_date: "2022-12-05T04:00:00Z" ,distance: 1000, time: 3600},{start_date: "2022-02-07T04:00:00Z" ,distance: 1500, time: 6400},{start_date: "2022-12-08T04:00:00Z" ,distance: 1000, time: 1300}]
let res = Object.values(x.reduce((acc,{start_date,distance,time})=> {
let month = new Date(start_date).getMonth()+1
if(!acc[month])acc[month] = {totalDistance:0,totalTime:0,month:month}
acc[month].totalDistance+=distance
acc[month].totalTime+=time
return acc;
},{}))
console.log(res)
You can use a object as a dictionary and save a accumulated value of time and distance per month key. Then, reduce all keys to an array with the requested format.
const groupPerMonth = (list) => {
const extractMonth = (stringDate) => {
const month = new Date(stringDate).getMonth() + 1;
return month < 10 ? `0${month}` : `${month}`;
}
const months = {};
for (const item of list) {
const month = extractMonth(item.start_date);
if (!(month in months)) {
months[month] = {
distance: 0,
total_time: 0,
};
}
months[month].distance += item.distance;
months[month].total_time += item.time;
}
const result = [];
for (const month in months) {
result.push({
month,
...months[month]
});
}
return result;
};
And test it:
console.log(
groupPerMonth([
{ start_date: "2022-12-05T04:00:00Z", distance: 1000, time: 3600 },
{ start_date: "2022-02-07T04:00:00Z", distance: 1500, time: 6400 },
{ start_date: "2022-12-08T04:00:00Z", distance: 1000, time: 1300 },
])
);
Output:
[
{ month: '12', distance: 2000, total_time: 4900 },
{ month: '02', distance: 1500, total_time: 6400 }
]
There might be different solutions to this, but one way to solve this is by using the lodash library to solve this. We can first group by month, followed by mapping each grouped item and adding the distance and time values in each group using reduce:
const list = [
{start_date: "2022-12-05T04:00:00Z" ,distance: 1000, time: 3600},
{start_date: "2022-02-07T04:00:00Z" ,distance: 1500, time: 6400},
{start_date: "2022-12-08T04:00:00Z" ,distance: 1000, time: 1300}
]
const grouped = _.groupBy(list, item => {
const date = new Date(item.start_date)
return date.getMonth() + 1
})
const groupedAndMapped = _.map(grouped, function(groupedList, date){
return {
month: date,
total_distance: _.reduce(groupedList, (total, current) => {
return total + current.distance
}, 0),
total_time:_.reduce(groupedList, (total, current) => {
return total + current.time
}, 0)
}
})
One improvement you could do is to format the month to an "MM-YYYY" format or something similar as its possible your data set can include items with different years.

Js return the start date and end date on a string

I have strings like this:
(Feb 28-Mar 1)
(Mar 2-3)
I would like me to return an object as you can see below, someone to give some suggestion how can I do?
function rD(text){
let date = text.replace('(', '').replace(')', '').split(' ');
//const [start, end] = date[2].split("-").map(Number);
return date;
}
console.log(rD("(Feb 28-Mar 1)"))
console.log(rD("(Mar 2-3)"))
Return:
[
{
month: 2,
day: 28
},
{
month: 3,
day: 1
}
]
[
{
month: 3,
day: 2
},
{
month: 3,
day: 3
}
]
I'd suggest using a regex pattern to parse each span.
From this we can get the startMonth, startDay, endMonth, endDay. We can then create a getMonthNumber() function to turn the abbreviated month name (Jan, Feb, etc.) to a number.
function getMonthNumber(month) {
const lookup = { jan: 01, feb: 02, mar: 03, apr: 04, may: 05, jun: 06, jul: 07, aug: 08, sep: 09, oct: 10, nov: 11, dec: 12};
return lookup[(month + '').toLowerCase()]
}
function parseSpan(str) {
const pattern = /\(([a-z]{3})\s+(\d{1,2})\-([a-z]{3})?\s?(\d{1,2})\)/i
const [, startMonth, startDay, endMonth, endDay] = str.match(pattern);
return [
{ month: getMonthNumber(startMonth), day: +startDay },
{ month: getMonthNumber(endMonth || startMonth), day: +endDay }
];
}
let testInputs = [
'(Feb 28-Mar 1)',
'(Mar 2-3)',
'(Sep 28-Oct 31)',
'(Jan 3-17)'
]
testInputs.map(parseSpan).forEach(span => console.log(span))
.as-console-wrapper { max-height: 100% !important; }
I'd remove the parentheses first and then split by /[ -]/. This way you get an array in one of these two forms
["Feb", "28", "Mar", "1"]
or
["Mar", "2", "3"]
Now if the array has 4 elements the first and third are always the month and second and forth are the day. If the array has 3 elements, the first is a month for both, start and end, the second and third are the days.
For getting the number of the month you can have a simple lookup like
{ Jan:1, Feb:2, ... }
let months = { Jan: 1, Feb: 2, Mar: 3 /* you get the idea*/}
let spans = ["(Jan 28 - Feb 3)", "(Mar 1-3)"]
let parse = (span) => {
let parts = span.replace(/[()]/g, "").split(/[ -]/).filter(x => !!x);
switch (parts.length) {
case 4: return [{month: months[parts[0]], date: +parts[1]}, {month: months[parts[2]], date: +parts[3]}];
case 3: return [{month: months[parts[0]], date: +parts[1]}, {month: months[parts[0]], date: +parts[2]}];
default: return undefined;
}
}
console.log(parse(spans[0]));
console.log(parse(spans[1]))
You can try this
function rangeCalcFunc(range = null) {
if(range && range.length){
const [start, end] = range.substring(1, range.length-1).split("-");
console.log(start);console.log(end);
const [startMon, startDt] = start.split(" ");
const [endMon, endDt] = end.split(" ");
return [
{
month: calcMonthInNumber(startMon.trim()),
date: startDt
},
{
month: calcMonthInNumber(endMon.trim()),
date: endDt
}
]
}
}
function calcMonthInNumber(month) {
switch(month.toLowerCase()){
case 'jan': return '01'
case 'feb': return '02'
//add for other months
default: break;
}
}
console.log(rangeCalcFunc("(Jan 28-Feb 1)"));
First we are going to create a mapper for the months. like this:
let MonthsMapper = new Map([['Jan', 1], ['Feb', 2], ['Mar', 3] /*...*/])
Then we need a function which cutes the string into chunks by removing the parenthesis and splitting it by its hyphen.
The first chunks are the start and end dates.
With these two dates we can further get the start month, start day, end month, and end day. (By splitting our chunks by there whitespaces)
There is only one special case I can see from your example and that is the case when the end date does not specify a month, in which case it is implicitly the start month.
let DateObjectParser = (dateString) => {
const [startDate, endDate] = dateString.replace(/[()]/g, '').split('-')
const [startMonth, startDay] = startDate.split(' ')
let [endMonth, endDay] = endDate.split(' ')
// in case a second month is not provided
if (endDay === undefined) {
endDay = endMonth
endMonth = startMonth
}
return [
{
month: MonthsMapper.get(startMonth),
day: parseInt(startDay),
},
{
month: MonthsMapper.get(endMonth),
day: parseInt(endDay),
}
]
}
Besides the code, the advantage to this approach is that it works if the input is something like Jan 1-3-Mar 7, while all the other answers don't put this into consideration, thus returning undefined or an error.
Simple regex and a list of month to numbers should work, and it seems the most straightforward to me. Using String.prototype.match we can "ignore" all the extra data (i.e. the parentheses and dashes between months), just extract the necessary data:
function rD(str) {
// have a list of the numbers of each month
const monthNum = {
jan: 1,
feb: 2,
mar: 3,
apr: 4,
may: 5,
jun: 6,
jul: 7,
aug: 8,
sep: 9,
oct: 10,
nov: 11,
dec: 12
};
// regex to extract the patterns "Feb 23" or "Aug 15-23"
let spl = str.match(/[a-z]{3} \d{1,2}(\-\d{1,2})?/gi);
// loop through matches
const result = spl.map(s => {
// first 3 letters is the month; get the month number
const month = monthNum[s.substr(0, 3).toLowerCase()],
rest = s.substr(4); // get the rest of the string sans the month and extra space
const e = rest.split("-");
return e.map(q => ({
month,
day: +q
}));
}).flat(); // our array may occasionally be multidimensional if the user provides something like "Nov 7-12". We flatten the array to fix that
return result;
}
console.log("(Feb 28-Mar 1):", rD("(Feb 28-Mar 1)"));
console.log("(Mar 2-3):", rD("(Mar 2-3)"));
console.log("(Nov 7-12-Dec 15):", rD("(Nov 7-12-Dec 15)"));
.as-console-wrapper { min-height: 100% !important; }
Added all the steps inline in below code snippet.
// const str = "(Feb 28-Mar 1)";
const str = "(Mar 2-3)";
// An Object which contains numeric value of months.
const monthMap = {
Jan: 1,
Feb: 2,
Mar: 3
};
/**
* convertStringToObject() method used to convert the input string into an object.
* #param : inputString
*/
function convertStringToObject(inputString) {
// Removing open and closed paranthesis and splitting the inputString with '-'
const split = inputString.replace('(', '').replace(')', '').split('-');
// If splitted array element does not contain month, appending that.
split[1] = (split[1].trim().length === 1) ? split[0].split(' ')[0] + ' ' + split[1] : split[1];
// Looping over the splitted array and then creating the object with keys 'month' and 'day'
return split.map((item) => {
const splittedItem = item.split(' ');
return {
month: monthMap[splittedItem[0]],
day: Number(splittedItem[1])
}
});
}
// Calling the convertStringToObject() method by passing the input string as a param.
console.log(convertStringToObject(str));

Array.sort() compare function returns undefined

I am trying to sort an array of string dates from oldest to newest. I set up a couple of compare functions, but the console is saying a is undefined. What is going wrong?
//Sort an array of dates in this format
const dates = [
'10',
'23 Apr 2018',
'01 Jun 1943',
'05 Aug 2055',
'22 Sep 1902'
'18 Aug 1970',
'01 Jan 1940',
'08 Mar 2018',
'11 Feb 1982',
'17 Mar 1927',
];
//remove the data that is not in the correct format
const cleanedDates = dates.filter(date => date.length === 11);
//isolate the day, convert to number
const getDay = (str) => {
return parseInt(str.slice(0,2));
};
//create a dictionary of months
const monthDict = {
Jan: 1,
Feb: 2,
Mar: 3,
Apr: 4,
May: 5,
Jun: 6,
Jul: 7,
Aug: 8,
Sep: 9,
Oct: 10,
Nov: 11,
Dec: 12
};
//get the month value via dictionary
const getMonth = (str) => {
const month = str.slice(3,6);
return monthDict[month];
};
//get the year, convert to number
const getYear = (str) => {
return parseInt(str.slice(7));
}
//comparison helper functions
//compare day
const compareDay = (a,b) => {
if (getDay(a) < getDay(b)) {
return -1;
} else if (getDay(a) === getDay(b)) {
return 0;
}
} else if (getDay(a) > getDay(b)) {
return 1;
}
};
//compare month
const compareMonth = (a,b) => {
if (getMonth(a) < getMonth(b)) {
return -1
} else if (getMonth(a) === getMonth(b)) {
compareDay(a,b);
} else if (getMonth(a) > getMonth(b)) {
return 1;
}
};
//compare year
const compareYear = (a,b) => {
if (getYear(a) < getYear(b)) {
return -1;
} else if (getYear(a) === getYear(b)) {
compareMonth(a,b);
}
} else if (getYear(a) > getYear(b)) {
return 1
}
};
//sort array
const sortedArray = cleanedDates.sort((a,b) => compareYear(a,b));
console.log(sortedArray);
your syntax is incorrect. The rest is working for me :). you are missing a , when you do const date on the value 22 Sep 1902. And there are extra } on two locations when you do an else if.
Fixing that will get it working:
//Sort an array of dates in this format
const dates = [
'10',
'23 Apr 2018',
'01 Jun 1943',
'05 Aug 2055',
'22 Sep 1902',
'18 Aug 1970',
'01 Jan 1940',
'08 Mar 2018',
'11 Feb 1982',
'17 Mar 1927'
];
//remove the data that is not in the correct format
const cleanedDates = dates.filter(date => date.length === 11);
//isolate the day, convert to number
const getDay = (str) => {
return parseInt(str.slice(0, 2));
};
//create a dictionary of months
const monthDict = {
Jan: 1,
Feb: 2,
Mar: 3,
Apr: 4,
May: 5,
Jun: 6,
Jul: 7,
Aug: 8,
Sep: 9,
Oct: 10,
Nov: 11,
Dec: 12
};
//get the month value via dictionary
const getMonth = (str) => {
const month = str.slice(3, 6);
return monthDict[month];
};
//get the year, convert to number
const getYear = (str) => {
return parseInt(str.slice(7));
}
//comparison helper functions
//compare day
const compareDay = (a, b) => {
if (getDay(a) < getDay(b)) {
return -1;
} else if (getDay(a) === getDay(b)) {
return 0;
} else if (getDay(a) > getDay(b)) {
return 1;
}
};
//compare month
const compareMonth = (a, b) => {
if (getMonth(a) < getMonth(b)) {
return -1
} else if (getMonth(a) === getMonth(b)) {
compareDay(a, b);
} else if (getMonth(a) > getMonth(b)) {
return 1;
}
};
//compare year
const compareYear = (a, b) => {
if (getYear(a) < getYear(b)) {
return -1;
} else if (getYear(a) === getYear(b)) {
compareMonth(a, b);
} else if (getYear(a) > getYear(b)) {
return 1
}
};
//sort array
const sortedArray = cleanedDates.sort((a, b) => compareYear(a, b));
console.log(sortedArray);
After cleaning the dates array and there is no syntax error, try this:
// convert to date
dates.map( el => new Date(el));
// sort it
dates.sort( (a,b) => a>b);

javascript insert object to array at specific point id and increment others id

I have little problem with js arrays. I want to insert object on if statement and increase id on anothers objects
var arr=[{asc_id:1, date:2018-06-29, name:"first"},
{asc_id:2, date:2018-06-30, name:"second"},
{asc_id:3, date:2018-07-10, name:"fourth"},
{asc_id:4, date:2018-07-10, name:"fifth"}];
var checkedItem={asc_id:4, date:2018-06-30, name:"third"};
let savingDate = moment(checkedItem.date)
var newArr = arr.map((item,key)=>{
if(savingDate.isSame(item.date) || savingDate.isAfter(item.date)){
console.log(true)
return{
//code here
}
}else{
return{
//code here
}
console.log(false)
}
})
console.log(newArr)
i want make new array looks like
newArr=[{asc_id:1, date:2018-06-29, name:"first"},
{asc_id:2, date:2018-06-30, name:"second"},
{asc_id:3, date:2018-06-30, name:"third"},
{asc_id:4, date:2018-07-10, name:"fourth"},
{asc_id:5, date:2018-07-10, name:"fifth"}];
map is not good idea? condition i check with momento and check statement is correct only i want how to push object between second and fourth and make asc_id as in code?
What you can do is make a deep copy of the original array. Then insert the new element in that array at the appropriate place, and then reset all the asc_id properties.
var arr=[{asc_id:1, date:"2018-06-29", name:"first"},
{asc_id:2, date:"2018-06-30", name:"second"},
{asc_id:3, date:"2018-07-10", name:"fourth"},
{asc_id:4, date:"2018-07-10", name:"fifth"}];
var checkedItem={asc_id:4, date:"2018-06-30", name:"third"};
var newArr = arr.map(e => Object.assign({}, e));
var insertPos = newArr.findIndex(({date}) => date > checkedItem.date);
if (insertPos == -1) { // If not found, insert at end
insertPos = newArr.length;
}
newArr.splice(insertPos, 0, checkedItem);
newArr.forEach((e, i) => e.asc_id = i + 1);
console.log(newArr);
.map is not a good idea because it returns an array with the same length as the one mapped, you can use a simple for loop and create an empty array to fill it with values from original array and push the checkedElement whenever matched , for the asc_id create a ndx and increment it:
var arr=[{asc_id:1, date:'2018-06-29', name:"first"},
{asc_id:2, date:'2018-06-30', name:"second"},
{asc_id:3, date:'2018-07-10', name:"fourth"},
{asc_id:4, date:'2018-07-10', name:"fifth"}];
var checkedItem={asc_id:4, date:'2018-06-30', name:"third"};
var newArr = [], ndx = 0;
arr.forEach((e,i) => {
newArr.push({ ...e, asc_id : ++ndx })
if(e.date === checkedItem.date)
newArr.push({...checkedItem, asc_id : ++ndx })
})
console.log(newArr)
Other answers re index the entire array, I'm not sure that's what you want, the following uses reduce and will only re index items after the inserted item.
const arr = [
{ asc_id: 5, date: "2018 - 06 - 29", name: "first" },
{ asc_id: 6, date: "2018 - 06 - 30", name: "second" },
{ asc_id: 8, date: "2018 - 07 - 10", name: "fourth" },
{ asc_id: 9, date: "2018 - 07 - 10", name: "fifth" }
];
const checkedItem = { asc_id: "ignored", date: "2018 - 06 - 30", name: "third" };
const addItem = (arr,newItem)=>{
let itemInserted=false;
const newArray = arr.reduce(
(result,item) => {
if(newItem.date.localeCompare(item.date) === -1){
if(!itemInserted){//item has not been inserted yet
result.push({...newItem,asc_id:item.asc_id});
itemInserted=true;
}
result.push({...item,asc_id:item.asc_id+1})
}else{
result.push(item)
}
return result;
},
[]//initial result
);
if(!itemInserted){//new item was the last item
newArray.push({...newItem,asc_id:arr.slice(-1)[0].asc_id+1});
}
return newArray;
}
console.log(addItem(arr,checkedItem));
Probably you could start implementing a function like the one I provide as part of the following runnable snippet.
Note that the first parameter is a condition: use moment or whatever to parse a date or operate with any property of any of the existing items.
See how insertWhen is a high order function which takes two different functions cond and comparer:
cond is a function that should return true or false when evaluating each given array item to find where to insert the new item.
compare is a function that should return -1 if you want to add the item before the found one, or 1 if you want to add the item after the found one. This function may use moment to return -1 or 1 depending on your needs.
Inserts the new item after the matched one
const arr = [{
asc_id: 1,
date: '2018 - 06 - 29',
name: "first"
},
{
asc_id: 2,
date: '2018 - 06 - 30',
name: "second"
},
{
asc_id: 3,
date: '2018 - 07 - 10',
name: "fourth"
},
{
asc_id: 4,
date: '2018 - 07 - 10',
name: "fifth"
}
]
const insertWhen = (cond, comparer, newItem, arr) => {
const foundItem = arr.find(cond)
if (!foundItem) return
let foundItemIndex = arr.indexOf(foundItem)
switch (comparer(foundItem, newItem)) {
case -1:
arr.splice(foundItemIndex + 1, 0, newItem)
arr.slice(foundItemIndex + 1)
.forEach(item => (item.asc_id = ++foundItemIndex + 1))
break
case 1:
arr.splice(foundItemIndex, 0, newItem)
arr.slice(foundItemIndex)
.forEach(item => (item.asc_id = ++foundItemIndex))
break
}
}
var newItem = {
asc_id: 4,
date: '2018-06-30',
name: "third"
}
insertWhen(
({ date }) => date == '2018 - 06 - 30',
(foundItem, newItem) => -1, // INSERT AFTER, wins foundItem
newItem,
arr
)
console.log(arr)
Inserts the new item before the matched one
const arr = [{
asc_id: 1,
date: '2018 - 06 - 29',
name: "first"
},
{
asc_id: 2,
date: '2018 - 06 - 30',
name: "second"
},
{
asc_id: 3,
date: '2018 - 07 - 10',
name: "fourth"
},
{
asc_id: 4,
date: '2018 - 07 - 10',
name: "fifth"
}
]
const insertWhen = (cond, comparer, newItem, arr) => {
const foundItem = arr.find(cond)
if (!foundItem) return
let foundItemIndex = arr.indexOf(foundItem)
switch (comparer(foundItem, newItem)) {
case -1:
arr.splice(foundItemIndex + 1, 0, newItem)
arr.slice(foundItemIndex + 1)
.forEach(item => (item.asc_id = ++foundItemIndex + 1))
break
case 1:
arr.splice(foundItemIndex, 0, newItem)
arr.slice(foundItemIndex)
.forEach(item => (item.asc_id = ++foundItemIndex))
break
}
}
var newItem = {
asc_id: 4,
date: '2018-06-30',
name: "third"
}
insertWhen(
({ date }) => date == '2018 - 06 - 30',
(foundItem, newItem) => 1, // INSERT BEFORE, wins the new item
newItem,
arr
)
console.log(arr)
arr.slice(0,idx).concat([element_to_insert].concat(arr.slice(idx+1,arr.length).map(n=>{
n.asc_id++;
return n;
})))

how to split the array list in separate array by day wise using javascript

how to split the array list by days
const days = [
{'name':'Mon','value':1},
{'name':'Tue','value':5},
{'name':'Wed','value':10},
{'name':'Wed','value':30},
{'name':'Fri','value':18},
{'name':'Sat','value':80},
{'name':'Sat','value':90},
{'name':'Sun','value':20},
]
I having the above array list by days i wed and Sat i am having two values for thu I am not having values. i need to split the repeated key values into separate array if day are not in the list i need to add zero value for that for example my out put will be
const result = [
[1,5,10,0,18,80,20],
[0,0,30,0,0,90,0]
]
I need like this result is it possible to do in javascript.
You can do this using native javascript.
The algorithm is very simple:
For each day in daysArray you should search it in your given array and just remove first occurence from days.
Do step 1 until days is empty. With the other words, execute step 1 until days.length == 0 condition is satisfied.
let days = [ {'name':'Mon','value':1}, {'name':'Tue','value':5}, {'name':'Wed','value':10}, {'name':'Wed','value':30}, {'name':'Fri','value':18}, {'name':'Sat','value':80}, {'name':'Sat','value':90}, {'name':'Sun','value':20} ], daysArray = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
let result = [];
while(days.length){
sub_array = [];
daysArray.forEach(function(item){
let index = days.findIndex(a => a.name == item);
if(index == -1)
sub_array.push(0);
else{
sub_array.push(days[index].value);
days.splice(index, 1);
}
});
result.push(sub_array);
}
console.log(result);
Add an array of days in the order that you want - daysList.
Group the day objects into a Map using the name as key - daysMap.
Reduce the daysList, and get the days objects from the map by the current day. Iterate the array of days with Array.forEach(), and for each add a week array filled with 0s if missing, and assign the day's value to the day index di.
const daysList = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
const days = [{"name":"Mon","value":1},{"name":"Tue","value":5},{"name":"Wed","value":10},{"name":"Wed","value":30},{"name":"Fri","value":18},{"name":"Sat","value":80},{"name":"Sat","value":90},{"name":"Sun","value":20}]
// group the days by name into a map
const daysMap = days.reduce((m, o) => {
m.has(o.name) || m.set(o.name, [])
m.get(o.name).push(o)
return m
}, new Map)
// iterate the daysList
const result = daysList.reduce((r, d, di) => {
//get the array of the days with the same name from the group
const daysObjs = daysMap.get(d) || []
//iterate the daysObjs array
daysObjs.forEach(({ name, value }, wi) => {
// add a new week array filled with 0 if the row is missing
r[wi] || r.push(new Array(daysList.length).fill(0))
// assign the day value to the week array
r[wi][di] = value
})
return r
}, [])
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You could take an object for the day indices and for the ouiter indixec which is incremented by every inset of data.
var days = [{ name: 'Mon', value: 1 }, { name: 'Tue', value: 5 }, { name: 'Wed', value: 10 }, { name: 'Wed', value: 30 }, { name: 'Fri', value: 18 }, { name: 'Sat', value: 80 }, { name: 'Sat', value: 90 }, { name: 'Sun', value: 20 }],
indices = { Mon: { day: 0, index: 0 }, Tue: { day: 1, index: 0 }, Wed: { day: 2, index: 0 }, Thu: { day: 3, index: 0 }, Fri: { day: 4, index: 0 }, Sat: { day: 5, index: 0 }, Sun: { day: 6, index: 0 } },
result = days.reduce((r, { name, value }) => {
r[indices[name].index] = r[indices[name].index] || Array.from({ length: 7 }).fill(0);
r[indices[name].index++][indices[name].day] = value;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use array#reduce and a lookup object of day and create an array of value based on a given day.
const days = [{'name':'Mon','value':1}, {'name':'Tue','value':5}, {'name':'Wed','value':10}, {'name':'Wed','value':30}, {'name':'Fri','value':18}, {'name':'Sat','value':80}, {'name':'Sat','value':90}, {'name':'Sun','value':20}, ],
day = {'Mon':0, 'Tue':1, 'Wed':2, 'Thu': 3, 'Fri': 4, 'Sat': 5, 'Sun': 6},
result = days.reduce((r,o) => {
var index = 0;
if(r[index][day[o.name]]) {
while(r[index] && r[index][day[o.name]]) {
index++;
}
if(!r[index]) {
r[index] = Array.from({length: 7}, _=> 0);
}
}
r[index][day[o.name]] = o.value;
return r;
},[Array.from({length: 7}, _=> 0)]);
console.log(result);
another solution:
const res = _.chain(days)
.map('name') // get days name
.uniq() // uniq days name
.map(day => _.filter(days, { name: day })) // iterate days name and get all day items
.map(sameDays => _.map(sameDays, 'value')) // get value for each day items
.map(vs => [vs[0], vs[1] || 0]) // set 0 value if only one item for day
.thru(_.spread(_.zip)) // transpose the array
.value()

Categories

Resources