I have an array that contains unique strings of day names. The day names will be in random order. - eg:
["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm"]
I want to use javascript to sort that array so that it will be in ascending order.
["Wed 3pm", "Sat 10am", "Sat 4pm", "Sun 10am", "Sun 4pm"]
Can anybody suggest the best way to do that?
Thank you
You can create a object with days names as keys and values increasing from 1 to 7.
Create a helper function which takes second part of string i.e 3pm,10am.. as input and add 12 to result if its pm
Also divide the result by 24 so first sort should happen on days.
Use the sort() function and for each value add the time index(which will be always less than 1) to the day index(1,2,3...) and subtract it for both value.
const arr = ["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm"];
function getTime(str){
let time = str.slice(0,-2);
let isAm = str.includes('am');
return (isAm ? +time : +time + 12)/24
}
function sortTime(arr){
let days = {
Mon:1,
Tue:2,
Wed:3,
Thur:4,
Fri:5,
Sat:6,
Sun:7
}
return arr.slice().sort((a,b) => {
let [day1,time1] = a.split(' ');
let [day2,time2] = b.split(' ');
return (days[day1] + getTime(time1)) - (days[day2] + getTime(time2))
})
}
console.log(sortTime(arr))
You could take an object for the values of the day and sort by the time.
const
getTime = string => {
var [day, hour, meridian] = string.match(/^(\D{3}) (\d+)(am|pm)/).slice(1),
days = { Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6, Sun: 7 };
return days[day] * 24 + +hour + (meridian === 'pm' && 12) + (hour === '12' && -12);
};
var array = ["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm", "Sat 12pm", "Sat 12am"];
array.sort((a, b) => getTime(a) - getTime(b));
console.log(array);
You can use the combination of map and sort. Here I am converting time in 24 Hours format for easy comparison of numbers.
var array = ["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm"],
mapping = { Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6, Sun: 7 },
result = array
.map((time, i) => {
const hour = parseInt(time.split(" ")[1], 10);
const hour24 = time.indexOf("am") > -1 ? hour : hour + 12;
return {
index: i,
day: mapping[time.split(" ")[0]],
hour24
}
})
.sort((a, b) => a.day - b.day || a.hour24 - b.hour24)
.map(({
index
}) => array[index]);
console.log(result);
Related
I have two array of objects and would like to compare start date of array 1 against array 2 to see if array 1 start date is within the range of array 2 start date and end date
Then also compare end date of array 1 against array 2 to see if array 1 end date is within the range of array 2 start date and end date
If both the condition above are met then validate if array 1 status is overlap.
eg: Dec 15-21 (array 1 - start date -end date ) Dec 18-31 (from array 2 start date -end date)
if array1 start date is outside the range of array 2 start and end date, then validate array 1 status is ready . and if array1 end date is outside the range of array 2 start and end date, then validate array 1 status is ready .
eg: Dec 01-07 (array 1 - start date -end date ) Dec 18-31 (from array 2 start date -end date)
If array 1 start date matches array 2 start date and array 1 end date matches array 2 end date then validate array 1 status is match,
eg: Dec 18-31 (array 1 - start date -end date ) Dec 18-31 (from array 2 start date -end date)
Firstly, I am comparing the month in the snippet so that dec months dates from array 1 are being compared only against dec month dates in array 2, likewise nov month dates from array 1 against nov month dates in array 2 etc. (this comparison works fine to validate all dec and nov month dates from array1)
Next, once date comparison is done for the matching months between array1 and array2(in this case dec and nov months are found in both array 1 and array2), I would like to return left out array objects from array 1 as a new array(say array3) in this case Jan, and Feb array objects.
Just my thoughts:
Overall, I want to return the final array that should remove all those elements(the array object) that satisfies any of the conditions ie if/else in the below code and return the new array at the end of the iteration.
The new array output should like the one mentioned below, and I can loop thru array3 and make sure that the rest of the array objects status is ready. (This is just my thought to extract Jan and feb months (as these months are not part of array2), and verify if all the other months except the ones found in array (in this case Dec and Nov) have the status as "ready".
(or) Please suggest if there is any better solution to verify the status of the array1 objects(jan,feb in this case) whose month is not found in array 2 and verify if the status is "ready".
Final output should be :
array3= [ {
start_date: "2022-01-01",
end_date: "2022-01-07",
},
{
start_date: "2022-02-16",
end_date: "2022-02-22",
}]
My current code
function compareTwoArrayOfObjects(array1, array2) {
array2.map(element => {
const start2 = new Date(element.start_date);
const end2 = new Date(element.end_date);
const start2Month = start2.getMonth();
const end2Month = end2.getFullYear();
console.log("####################################")
return array1.map(elm_arr1 => {
const start1 = new Date(elm_arr1.start_date);
const end1 = new Date(elm_arr1.end_date);
let status;
const start1Month = start1.getMonth();
const end1Month = end1.getFullYear();
if (start1.getTime() === start2.getTime() && end1.getTime() === end2.getTime() && ((start1Month === start2Month) || (end1Month === start2Month))) {
console.log("**************")
status = "match";
console.log(start1, end1)
console.log(start2, end2)
console.log(start1Month, start2Month)
console.log(elm_arr1.status)
//expect(elm_arr1.status).toMatch("match");
console.log("**************")
} else if (((start1Month === start2Month) || (end1Month === start2Month)) && ((start1 > start2 && start1 < end2) || (end1 > start2 && end1 < end2) || (start2 > start1 && start2 < end1) || (end2 > start1 && end2 < end1))) {
status = "overlap";
console.log("**************")
console.log(start1, end1)
console.log(start2, end2)
console.log(start1Month, start2Month)
console.log(elm_arr1.status)
// expect(elm_arr1.status).toMatch("overlap");
console.log("**************")
} else if (((start1Month === start2Month) || (end1Month === start2Month)) && ((start1 < start2 && end1 < start2) || (start1 > end2 && end1 > end2))) {
status = "ready";
console.log("**************")
console.log(start1, end1)
console.log(start2, end2)
console.log(start1Month, start2Month)
console.log(elm_arr1.status)
//expect(elm_arr1.status).toMatch("ready");
console.log("**************")
}
});
});
}
const result = compareTwoArrayOfObjects(array1, array2);
<script>
let array1 = [{
start_date: "Dec 01 2022",
end_date: "Dec 07 2022",
status: "ready"
},
{
start_date: "Dec 04 2022",
end_date: "Dec 10 2022",
status: "ready"
},
{
start_date: "Dec 15 2022",
end_date: "Dec 21 2022",
status: "overlap"
},
{
start_date: "Dec 18 2022",
end_date: "Dec 24 2022",
status: "overlap"
},
{
start_date: "Dec 12 2022",
end_date: "Dec 28 2022",
status: "overlap"
},
{
start_date: "Dec 25 2022",
end_date: "Dec 31 2022",
status: "overlap"
},
{
start_date: "Nov 22 2022",
end_date: "Nov 28 2022",
status: "match"
},
{
start_date: "Nov 01 2022",
end_date: "Nov 07 2022",
status: "ready"
},
{
start_date: "Jan 01 2022",
end_date: "Jan 07 2022",
status: "ready"
},
{
start_date: "Feb 16 20226",
end_date: "Feb 22 2022",
status: "ready"
},
];
let array2 = [{
start_date: "Dec 18 2022",
end_date: "Dec 31 2022"
},
{
start_date: "Nov 22 2022",
end_date: "Nov 28 2022"
},
];
</script>
so I am using the momentJS library as the moment to create an array of 7 days in a week like this:
const moment = require('moment')
var startOfWeek = moment().startOf('week');
var endOfWeek = moment().endOf('week');
var days = [];
var day = startOfWeek;
while (day <= endOfWeek) {
days.push(day.format("MMMM ddd DD, YYYY "));
day = day.clone().add(1, 'd');
}
console.log(days);
And the result return an array of 7 days a week like this:
["December Sun 25, 2022 ","December Mon 26, 2022 ", "December Tue 27, 2022 " , "December Wed 28, 2022 ", "December Thu 29, 2022 ", "December Fri 30, 2022 ", "December Sat 31, 2022 "]
But the result that I look for is something like this:
const weekday = [
{
day: Mon,
date: 26
},
{
day: Tue,
date: 27
},
{
day: Wed,
date: 28
},
{
day: Thu,
date: 26
},
{
day: Fri,
date: 26
},
{
day: Sat,
date: 26
},
]
I am stuck on how to convert the data, could anyone able to help me ? Thanks
Without momentjs, you can use toLocaleDateString and other native Date methods to achieve the result:
const day = new Date(); // Today
day.setDate(day.getDate() - day.getDay() - 1); // Most recent Saturday (not today)
const weekday = Array.from({length: 7}, () => (
day.setDate(day.getDate() + 1), {
day: day.toLocaleDateString("en-US", { weekday: "short" }),
date: day.getDate(),
}
));
console.log(weekday);
If you wish to keep the original output to use elsewhere and not modify the original code, you can map over the days array and construct a new array based on the formatted string (converting to an integer as necessary).
const days = ["December Sun 25, 2022 ", "December Mon 26, 2022 ", "December Tue 27, 2022 ", "December Wed 28, 2022 ", "December Thu 29, 2022 ", "December Fri 30, 2022 ", "December Sat 31, 2022 "]
const weekday = days.map((formattedDate) => {
const [_, day, dateString] = formattedDate.split(" ");
return {
day,
date: parseInt(dateString)
};
});
console.log(weekday);
Alternatively, you can modify your original code
//const moment = require('moment')
const startOfWeek = moment().startOf('week');
const endOfWeek = moment().endOf('week');
// uncomment if you still want `days`
// const days = [];
const weekday = [];
let day = startOfWeek;
while (day <= endOfWeek) {
// days.push(day.format("MMMM ddd DD, YYYY "));
weekday.push({ day: day.format("ddd"), date: day.date() });
day = day.clone().add(1, 'd');
}
console.log(weekday);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
I'm referring to this answer again.
var firstEvents = events.reduce(function(ar, e) {
var id = e.getId();
if (e.isRecurringEvent() && e.isAllDayEvent() && !ar.some(function(f) {return f.eventId == id})) {
ar.push({eventTitle: e.getTitle(), eventId: id, startDate: e.getAllDayStartDate(), endDate: e.getAllDayEndDate()});
}
return ar;
}, []);
What do I have to change to get an array with the event titles (Strings) as keys and the start dates (Date objects) as values so I can retrieve a certain start date (Date object) via firstEvents['some event title']?
EDIT:
Current Ouput:
firstEvents = [{eventTitle=Event title 1, eventId=xyz1#google.com, startDate=Sun Mar 18 00:00:00 GMT+01:00 2018, endDate=Mon Mar 19 00:00:00 GMT+01:00 2018},
{eventTitle=Event title 2, eventId=xyz2#google.com, startDate=Tue Mar 19 00:00:00 GMT+01:00 2019, endDate=Wed Mar 20 00:00:00 GMT+01:00 2019},
{eventTitle=Event title 3, eventId=xyz3#google.com, startDate=Fri Mar 20 00:00:00 GMT+01:00 2020, endDate=Sat Mar 21 00:00:00 GMT+01:00 2020}]
Needed Output (Pseudo):
firstEvents = ['Event title 1' => Sun Mar 18 00:00:00 GMT+01:00 2018,
'Event title 2' => Tue Mar 19 00:00:00 GMT+01:00 2019,
'Event title 3' => Fri Mar 20 00:00:00 GMT+01:00 2020]
Do not use push, but set to object with key.
ar = {}; // You may need to change source parameter too
// you cannot change input Array [] to Object {} type inside function
// you can get Array and return Object, but source variable will not change
ar[e.getTitle()] = e.getAllDayStartDate();
Or using some demo data:
var ar = [
{
eventTitle: 'one',
eventId: '#1',
startDate: new Date(),
endDate: new Date()
},
{
eventTitle: 'two',
eventId: 'secondId',
startDate: new Date(),
endDate: new Date()
}];
var retVal = {};
for (var i of ar) {
retVal[i.eventId] = i;
}
console.log(JSON.stringify(retVal, null, 2));
console.log(retVal['#1']);
console.log(retVal.secondId);
Given the following Dates:
var b = [
{Date:'Jan 2016', steel:10.98},
{Date:'Feb 2016', steel:5.67},
{Date:'Jan 2016', steel:3.14},
{Date:'Feb 2016', steel:2.14},
{Date:'Mar 2016', steel:12.14}
]
I want to calculate both sum and cumulative average with respect to the dates shown above.
My desired output is:
Sum ->
[{"Date": "Jan 2016","val": 14.12},
{"date": "Feb 2016","val": 7.81},
{"date": "Mar 2016","val": 12.14}]
Cumulative Average ->
[{"Date": "Jan 2016","val": 7.06 },
{"date": "Feb 2016","val": 5.48},
{"date": "Mar 2016","val": 6.814}]
const sumSteelAndConcrete = (s = { steel: 0 }, c = { steel: 1 }) => s.steel + c.steel;
const findByDate = (arr, date) => arr.find(item => item.Date === date);
const result = dates.map(
sumSteelAndConcrete(
findByDate(steelDays, date),
findByDate(steelDays, date)
)
)
);
var array = [{
id: 1,
date: 'Mar 12 2017 10:00:00 am'
},{
id: 2,
date: 'Mar 12 2017 08:00:00 pm'
},{
id: 3,
date: 'Mar 12 2017 05:00:00 am'
},{
id: 4,
date: 'Mar 18 2017 09:00:00 am'
}];
Here is my logic:-
sortedPatients = PatientsListArray.sort((a, b) => {
if (b.Date < a.Date) return -1
if (b.Date > a.Date) return 1
})
I'm getting output like this id4 , id1 , id2 , id3
I expected output like this id4, id2, id3, id1
Can anyone help me?
Your code have some issues:
You're comparing Strings rather than Date objects, So, you're sorting Strings :-)
if (b.Date < a.Date) return -1
^ ^
You're getting the Date string using a capitalized Date attribute.
if (b.Date < a.Date) return -1
^ ^
What you're expecting is incorrect because you want to get a Descending result id4, id2, id1, id3
id4, id2, id3, id1
^ ^
->
<-
Your source array contains an invalid value for date attribute, so you need to wrap it with quotes ".
date: Mar 12 2017 10:00:00 am
^ ^
You can use either new Date() constructor or the static function Date.parse (to get number of milliseconds since January 1, 1970, 00:00:00 UTC).
new Date()
String value representing a date. The string should be in a format recognized by the Date.parse() method (IETF-compliant RFC 2822 timestamps and also a version of ISO8601).
Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local. Reference
Date.parse()
The parse() method takes a date string (such as "Dec 25, 1995") and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC. This function is useful for setting date values based on string values, for example in conjunction with the setTime() method and the Date object. Reference
Look this code snippet with those fixes:
var array = [{
id: 1,
date: 'Mar 12 2017 10: 00: 00 am'
}, {
id: 2,
date: 'Mar 12 2017 08: 00: 00 pm'
}, {
id: 3,
date: 'Mar 12 2017 05: 00: 00 am'
}, {
id: 4,
date: 'Mar 18 2017 09: 00: 00 am'
}];
var sorted = array.sort((a, b) => {
//The parse function will convert those strings to Dates.
var bdt = Date.parse(b.date);
var adt = Date.parse(a.date);
return bdt > adt ? 1 : (bdt < adt ? -1 : 0);
});
console.log(sorted);
See? now your logic is working!
Your sort logic is correct. The issue is because your date properties in the objects of your array are strings (despite the sample in your question missing the quotes delimiting the values - I presume you copy/pasted this from your console). Therefore they are compared alphanumerically. To fix this you need to convert them to Date() objects so the date comparison can be made.
Also note that JS is case-sensitive, so a.Date is not equal to a.date. Try this:
var array = [{
id: 1,
date: 'Mar 12 2017 10:00:00 am'
},{
id: 2,
date: 'Mar 12 2017 08:00:00 pm'
},{
id: 3,
date: 'Mar 12 2017 05:00:00 am'
},{
id: 4,
date: 'Mar 18 2017 09:00:00 am'
}];
var sortedPatients = array.sort((a, b) => {
var aDate = new Date(a.date), bDate = new Date(b.date);
if (bDate < aDate) return -1
if (bDate > aDate) return 1
})
console.log(sortedPatients);
Assuming your date string is a parsable string (RFC2822 or (a variant of) ISO 8601 date) you can map your data to a tuple (array) of parsed date string and the index of that date. Then sort on the parsed date string (milliseconds after epoch) and then rebuild a new array using the indexes of the sorted array and original data.
var array = [{
id: 1,
date: 'Mar 12 2017 10:00:00 am'
},{
id: 2,
date: 'Mar 12 2017 08:00:00 pm'
},{
id: 3,
date: 'Mar 12 2017 05:00:00 am'
},{
id: 4,
date: 'Mar 18 2017 09:00:00 am'
}];
var sorted = array.map(//map to tuple of epoch ms date and index
({date},index)=>[Date.parse(date),index]
)
.sort(//sort on epoch ms date
(a,b)=>a[0]-b[0]
).reduce(//rebuild an array based on sorted indexes
(all,[_,index])=>
all.concat([array[index]]),
[]
);
You are using string comparison. You have to Date.parse to get timestamp in number
array.sort((a, b) => Date.parse(b.date) - Date.parse(a.date))