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));
I am trying to exclude different times based on dates but the times are disabled no matter what dates I pick. For example if I select the 28th Of September then 12 o'clock should be disabled. If I choose the 3rd of October then 1pm should disabled, however 12 and 1 are disabled right from the start and stay that way no matter what date I pick.
https://hacker0x01.github.io/react-datepicker
const isSunday = (date) => {
const day = getDay(date);
return day !== 0;
};
let excluded = [
{
time: "12",
date: "28/09/2020",
},
{
time: "13",
date: "03/10/2020",
},
];
<DatePickerField
filterDate={isSunday}
minTime={new Date(new Date().setHours(8, 0, 0))}
maxTime={new Date(new Date().setHours(17, 0, 0))}
excludeTimes={excluded.map((exclude, index) => {
return setHours(
setMinutes(new Date(), 0),
parseInt(exclude.time)
);
})}
timeIntervals={60}
maxDate={addDays(new Date(), 3)}
dateFormat="d/M/Y HH:mm"
timeFormat="HH:mm"
name="time-to-contact"
label="Required Date *"
/>
The problem is you are always returning excluded in excludeTimes props. You need to return the time only if the selected date is the date. Something like that should work. (By adding const [value, setValue] = useState(); too).
<DatePickerField
filterDate={isSunday}
minTime={new Date(new Date().setHours(8, 0, 0))}
maxTime={new Date(new Date().setHours(17, 0, 0))}
excludeTimes={excluded.map((exclude) => {
const excDate = new Date(exclude.date);
if (
value &&
excDate.getDate() === value.getDate() &&
excDate.getFullYear() === value.getFullYear() &&
excDate.getMonth() === value.getMonth()
) {
return new Date(new Date().setHours(exclude.time, 0, 0));
}
return null;
})}
timeIntervals={60}
maxDate={addDays(new Date(), 3)}
dateFormat="d/M/Y HH:mm"
timeFormat="HH:mm"
name="time-to-contact"
label="Required Date *"
onChange={(e) => {
setValue(new Date(e));
}}
selected={value}
/>
Also your dates are not in the good format for JS, it should be:
const excluded = [
{
time: "12",
date: "09/28/2020"
},
{
time: "13",
date: "10/03/2020"
}
];
Here's a link to a working example: https://codesandbox.io/s/competent-smoke-4nv1e?file=/src/App.js
To add exclude time for a specific day (let's say monday) you could use this:
const excluded = [
{
time: "12",
day: 1
},
]
And set the prop to this:
excludeTimes={excluded.map((exclude) => {
if (value && value.getDay() === exclude.day) {
return new Date(new Date().setHours(exclude.time, 0, 0));
}
return null;
})}
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]));
I have an array of objects like this:
var json = [ { day: '01-01-2018', hour: '00:00', value: '121' }, { day: '01-02-2018', hour: '05:24', value: '131' }, { day: '26-01-2018', hour: '00:07', value: '101' }, { day: '16-02-2018', hour: '08:02', value: '56' }, { day: '20-02-2018', hour: '12:02', value: '123' }, { day: '24-03-2018', hour: '10:11', value: '45' }];
I would like to change format of date from DD-MM-YYYY to YYYY-MM-DD and then sum values per month to create a chart.
My attempt:
var mapDateVolume = [];
for (var i = 0; i < json.length; i++)
{
var allDate = json[i].day;
var oneVolume = json[i].value;
var splitedDate = allDate.split("-");
var newOrderY = splitedDate[2] + "-"
var newOrderM = splitedDate[1] + "-";
var newOrderD = splitedDate[0];
var newOrderAllDate = newOrderY + newOrderM + newOrderD;
var newOrder = {};
newOrder[newOrderAllDate] = oneVolume;
mapDateVolume.push(newOrder);
}
var result = [];
for (var i = 0; i < mapDateVolume.length; i++){
var key = Object.keys(mapDateVolume)[i].split("-")[0] + "/";
key += Object.keys(mapDateVolume)[i].split("-")[1];
var value = Object.values(mapDateVolume)[i];
var oldValue = Object.keys(result)[i] != null ? Object.keys(result)[i] : 0;
var newResult = {};
newResult[key] = value;
result.push(newResult);
}
for (var i = 0; i < result.length; i++) {
xAxis.push(Object.keys(result)[i]);
yAxis.push(Object.values(result)[i]);
}
I use Chart.js and it works fine with days:
for ( var i = 0; i < jsonAll.length; i++ )
{
xAxis.push(json[i].day+'-'+json[i].hour);
yAxis.push(json[i].value);
}
I know that something is wrong with this sum because I see only an empty chart. Unfortunately, I have little experience with JavaScript.
First of all lets format whole collection (data array).
We need to:
Date format: DD-MM-YYYY to YYYY-MM-DD.
Value property is a string type we need it as number.
Simple with Array#Map:
const collection = data.map(x => ({ ...x, day: x.day.split("-").reverse().join("-"), value: Number(x.value)}));
Next thing is to use again Array#Map to replace day property to Month.
const mapDayToMonth = collection.map(x => ({...x, day: new Date(x.day).getMonth()}));
The getMonth() method returns the month (from 0 to 11) for the specified date, according to local time. So, 0 is January, 1 is February ...etc
Last step Array#Reduce to sum value per Month:
const sumPerMonth = mapDayToMonth.reduce((acc, cur) => {
acc[cur.day] = acc[cur.day] + cur.value || cur.value;
return acc;
}, {})
Full example JSFiddle:
const data = [ { day: '01-01-2018', hour: '00:00', value: '121' }, { day: '01-02-2018', hour: '05:24', value: '131' }, { day: '26-01-2018', hour: '00:07', value: '101' }, { day: '16-02-2018', hour: '08:02', value: '56' }, { day: '20-02-2018', hour: '12:02', value: '123' }, { day: '24-03-2018', hour: '10:11', value: '45' }];
const collection = data.map(x => ({ ...x, day: x.day.split("-").reverse().join("-"), value: Number(x.value)}));
console.log(collection);
const mapDayToMonth = collection.map(x => ({...x, day: new Date(x.day).getMonth()}));
console.log(mapDayToMonth);
const sumPerMonth = mapDayToMonth.reduce((acc, cur) => {
acc[cur.day] = acc[cur.day] + cur.value || cur.value; // increment or initialize to cur.value
return acc;
}, {})
console.log(sumPerMonth)
Useful links:
Array Map
Array Reduce
Number Object
Spread Syntax
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()