says you have this array [0,1,2,3,4,5,6], 0 represent sunday, 1 represent monday... till the 6 represent saturday.
I want to produce string output like below:
weekdays //[1,2,3,4,5]
weekends //[0,6]
mon, tue, wed //[1,2,3]
it can also be mixed group like,
weekends, thu //[0,6,4]
weekdays, sat //[1,2,3,4,5,6]
*The comment is input, and the output is on the left.
Tried moment but couldn't find any method to parse it.
Here's my take at it. Hope it helps.
const week = {
SUNDAY: 0,
MONDAY: 1,
TUESDAY: 2,
WEDNESDAY: 3,
THURSDAY: 4,
FRIDAY: 5,
SATURDAY: 6,
weekday: [1,2,3,4,5],
weekend: [0,6]
};
let array1 = [1,2,3,4,5]; //weekdays
let array2 = [0,6]; //weekends
let array3 = [1,2,3]; //mon, tue, wed
let array4 = [0,6,4]; //weekends, thu
let array5 = [1,2,3,4,5,6]; //weekdays, sat
let keys = Object.keys(week);
let values = Object.values(week);
function parseArray(array) {
let isWeekend = week.weekend.every((val) => array.includes(val));
let isWeek = week.weekday.every((val) => array.includes(val));
let foundDays = [];
//console.log("Contains Weekend: " + isWeekend);
//console.log("Contains Week: " + isWeek);
isWeekend ? foundDays.push("Weekend") : null;
isWeek ? foundDays.push("Weekdays") : null;
for (let i = 0; i < array.length; i++) {
let foundIndex = values.indexOf(array[i]);
if (isWeek && foundIndex > 0 && foundIndex < 6) {
continue;
}
if (isWeekend && (foundIndex === 0 || foundIndex === 6)) {
continue;
}
if (foundIndex > -1) {
foundDays.push(keys[foundIndex]);
}
}
console.log(foundDays);
}
parseArray(array1);
parseArray(array2);
parseArray(array3);
parseArray(array4);
parseArray(array5);
I don't think you can do this with moment. I would create a function to do this for you.
Something like below.
function getDays(input) {
const ref = {
weekdays: [1, 2, 3, 4, 5],
weekends: [0, 6],
sun: [0],
mon: [1],
tue: [2],
wed: [3],
thu: [4],
fri: [5],
sat: [6]
}
let output = []; //this will hold array of output days
//Check for each combination in ref object
for (prop in ref) {
let isPresent = ref[prop].every(item => {
return input.indexOf(item) !== -1;
});
//if the combination is present add to output and remove those days from input
if (isPresent) {
output.push(prop);
input = input.reduce((acc, value) => {
if (ref[prop].indexOf(value) !== -1) {
return acc;
} else {
acc.push(value);
return acc;
}
}, []);
}
}
return output.join(', ');
}
console.log(getDays([1, 2]));
console.log(getDays([0, 3, 6]));
console.log(getDays([1, 2, 3, 4, 5]));
Simple approach:-
var daysOfWeek = [0,1,2,3,4,5,6,[0,6],[1,2,3,4,5]];
var dayNames = ['sun','mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'weekends','weekdays' ];
function mapDescriptionWithDays(inpString){
inpArray=inpString.split(',');
var output='';
for(i=0; i< inpArray.length ; i++){
output += ','+daysOfWeek[dayNames.indexOf((inpArray[i]).trim())];
}
output=output.substring(1);
output='[' + output +']';
return output;
}
var a = mapDescriptionWithDays('weekdays, sat');
alert(a);
How about this:
function getHumanDescription(daysArray) {
const dayNames = [ 'sat', 'mon', 'tue', 'wed', 'thu', 'fri', 'sun' ]
const weekdays = [1,2,3,4,5]
const weekend = [0,6]
let description = []
if(weekdays.every(day => daysArray.includes(day))) {
description.push('weekdays')
daysArray = daysArray.filter(day => !weekdays.includes(day))
}
if(weekend.every(day => daysArray.includes(day))) {
description.push('weekends');
daysArray = daysArray.filter(day => !weekend.includes(day))
}
daysArray.forEach(day => description.push(dayNames[day]))
return description.join(', ')
}
console.log(getHumanDescription([0,1,2,3,4,5,6]));
console.log(getHumanDescription([0,5,6]));
console.log(getHumanDescription([1,2,3,4,5,6]));
console.log(getHumanDescription([1,3,4,5,6]));
Related
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));
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)
});
I am building a chart for monthly data which would have the x axis as wk1 - wk4 and y axis being the amount of goods etc. I was able to build out a solution but the problem lies when there is no data for a particular week. This is my code below.
const byAmount = obj => {
const res = [];
const keys = Object.keys(obj);
keys.forEach(key => {
res.push({
week: `wk${key}`,
amount: obj[key]
});
});
return res.sort((a, b) => a.amount - b.amount).slice(0, 5);;
};
const getWeeklyFromMonth = (arr, month) => {
const week = arr.map(a => ({ ...a, week: Math.floor((moment(a.dateScanned.$date).date() - 1) / 7) + 1 }));
let dataForMonth = [];
let total;
week.map(data => {
if (moment(data.dateScanned.$date).format("MMM") === month) {
dataForMonth.push(data);
const totalPerWeek = dataForMonth.reduce((acc, cur) => {
acc[cur.week] = acc[cur.week] + cur.amount || cur.amount;
return acc;
}, {});
total = totalPerWeek;
}
});
return byAmount(total);
}
When I run this I get the below:
[
{ week: 'wk1', amount: 14 },
{ week: 'wk2', amount: 27 },
{ week: 'wk4', amount: 43 }
]
This is fine but I want to populate the array with 0 if there is no data say for week 3. I would want it to be this
[
{ week: 'wk1', amount: 14 },
{ week: 'wk2', amount: 27 },
{ week: 'wk3', amount: 0 },
{ week: 'wk4', amount: 43 }
]
I was thinking of having an array of like [1, 2, 3, 4] and if the array includes the week number, pop it out of the array and then the remaining item should be used to populate it but I find myself scratching my head. Does anyone know a decent way to do this?
Thank you in advance.
You can try this:
const byAmount = obj => {
const res = [];
const keys = Object.keys(obj);
const [min, max] = [Math.min(...keys), Math.max(...keys)];
for(let key = min; key <= max; key++) {
res.push({
week: `wk${key}`,
amount: obj[key] || 0
});
}
return res.sort((a, b) => a.amount - b.amount).slice(0, 5);;
};
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);
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()