Modifying JS Array based on some conditions - javascript

var arr = [{"Event_code":"AB-001","Interest_area":"Arts","Start_time":"9:00 AM","End_time":"3:00 PM","Session_type":"Course information session"},{"Event_code":"AB-002","Interest_area":"Arts","Start_time":"12:30 PM","End_time":"1:00 PM","Session_type":"Course information session"},{"Event_code":"AB-003","Interest_area":"","Start_time":"9:00 AM","End_time":"3:00 PM","Session_type":"Course information session"},{"Event_code":"AB-004","Interest_area":"Business","Start_time":"10:30 AM","End_time":"11:00 AM","Session_type":"Course information session"},{"Event_code":"AB-005","Interest_area":"General Interest","Start_time":"9:00 AM","End_time":"1:30 PM","Session_type":"Experience"},{"Event_code":"AB-006","Interest_area":"Environment , Business ","Start_time":"11:00 AM","End_time":"11:30 AM","Session_type":"Course information session"}];
var st = {};
arr.forEach(o => {
if(st[o.Start_time]) o.clash = "yes";
else st[o.Start_time] = o.Start_time;
var diff = ( new Date("1970-1-1 " + o.End_time) - new Date("1970-1-1 " + o.Start_time) ) / 1000 / 60 / 60;
//console.log(diff); // hours
if (diff > 5){
o.duration = "Full day event";
}
});
console.log(arr);
What I am trying to do is add 2 key value pairs based on 2 conditions ..
Cond 1. Add "Clash":" Yes" if 2 events have a same start time
Cond 2: Add "Duration:"Full Day event" if "Start time" and "end time" have a difference of more than 5 hours.
The above code is not printing "clash":"Yes" pair.
This question has helped me greatly with Condition 1. I just want to add Condition 2 now.

For setting clash, you could take an object with start time and the actual index.
If another event starts at the time, set clash to both of the objects.
var array = [{ Event_code: "AB-001", Interest_area: "Arts", Start_time: "9:00 AM", End_time: "3:00 PM", Session_type: "Course information session" }, { Event_code: "AB-002", Interest_area: "Arts", Start_time: "12:30 PM", End_time: "1:00 PM", Session_type: "Course information session" }, { Event_code: "AB-003", Interest_area: "", Start_time: "9:00 AM", End_time: "3:00 PM", Session_type: "Course information session" }, { Event_code: "AB-004", Interest_area: "Business", Start_time: "10:30 AM", End_time: "11:00 AM", Session_type: "Course information session" }, { Event_code: "AB-005", Interest_area: "General Interest", Start_time: "9:00 AM", End_time: "1:30 PM", Session_type: "Experience" }, { Event_code: "AB-006", Interest_area: "Environment, Business", Start_time: "11:00 AM", End_time: "11:30 AM", Session_type: "Course information session" }],
clash = Object.create(null);
array.forEach((o, i, a) => {
var diff = (new Date("1970-1-1 " + o.End_time) - new Date("1970-1-1 " + o.Start_time)) / 1000 / 60 / 60;
//console.log(diff); // hours
if (diff > 5) {
o.duration = "Full day event";
}
if (o.Start_time in clash) {
a[clash[o.Start_time]].clash = true; // set first found
o.clash = true; // set actual item
return;
}
clash[o.Start_time] = i; // save index
});
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I changed your code a bit and here is new working code

Related

Comparing two arrays of objects and removing when two match

I was wondering if anyone could help me. I am using React and I have two arrays of objects:
one for all possible booking times
the other for existing bookings.
I am struggling to find a way of successfully looping over the allSlots array and removing any that have a matching time inside the existingBookings array.
In the example below, there are existing bookings at 10:00am, 10:40am, 11:00am and 11:20am.
The expected output would only leave 10:20am and 11:40am from the original array.
const allSlots = [
{
date: "28 Sept 22",
time: "10:00am"
},
{
date: "28 Sept 22",
time: "10:20am"
},
{
date: "28 Sept 22",
time: "10:40am"
},
{
date: "28 Sept 22",
time: "11:00am"
},
{
date: "28 Sept 22",
time: "11:20am"
},
{
date: "28 Sept 22",
time: "11:40am"
}
];
const existingBookings = [
{
time: "10:00am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "Bq4b3uz129aE2D5TCbaOiLQJrvC2",
date: "28 Sept 22"
},
{
time: "11:00am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "Ko2LdnQAdaE2OiLQJrvC2D5TCbA",
date: "28 Sept 22"
},
{
time: "10:40am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "Ko2LdnQAdaE2OiLQJrvC2D5TCbA",
date: "28 Sept 22"
},
{
time: "11:20am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "iLQJrKo2LdCbnQAdaE2OvC2D5TA",
date: "28 Sept 22"
}
];
I originally filtered the existingBookings data down to remove any that did not match the selected date with:
const existingBookings = allBookings.filter(
(booking) => booking.date === selectedDate
);
However, I am struggling to manipulate things further. I really appreciate any insight and help you may be able to give.
It is as simple as doing
freeSlots=allSlots.filter(s=>
existingBookings.every(e=>e.time!=s.time||e.date!=s.date)
)
Here is a working (plain) JavaScript snippet:
const allSlots = [
{
date: "28 Sept 22",
time: "10:00am"
},
{
date: "28 Sept 22",
time: "10:20am"
},
{
date: "28 Sept 22",
time: "10:40am"
},
{
date: "28 Sept 22",
time: "11:00am"
},
{
date: "28 Sept 22",
time: "11:20am"
},
{
date: "28 Sept 22",
time: "11:40am"
}
];
const existingBookings = [
{
time: "10:00am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "Bq4b3uz129aE2D5TCbaOiLQJrvC2",
date: "28 Sept 22"
},
{
time: "11:00am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "Ko2LdnQAdaE2OiLQJrvC2D5TCbA",
date: "28 Sept 22"
},
{
time: "10:40am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "Ko2LdnQAdaE2OiLQJrvC2D5TCbA",
date: "28 Sept 22"
},
{
time: "11:20am",
propertyID: "XQPvl7MmLVNtxHdSRfDq",
userID: "iLQJrKo2LdCbnQAdaE2OvC2D5TA",
date: "28 Sept 22"
}
];
const freeSlots=allSlots.filter(s=>
existingBookings.every(e=>e.time!=s.time||e.date!=s.date)
)
console.log(freeSlots);
You want to filter your allSlots array so that it only contains slots not present in existingBookings
const unusedSlots = allSlots.filter((slot) => {
// See if the slot is booked
const isBooked = existingBookings.some(
(booking) => booking.time == slot.time && booking.date == slot.date
)
// Only keep free slots
return !isBooked
});
This should work.
const newAllSlots = allSlots.filter((slot)=>{
const iSInExistingBookings = existingBookings.find(booking=>booking.time === slots.time && booking.date === slots.date)
return !iSInExistingBookings
})
Since you know what you already have booked with existingBookings, I would suggest looping through that first. Then you can recursively filter the allSlots array back into itself by checking if the date matches but the time does not. Once completed, the allSlots array should only have the date and times that haven't been booked.
existingBookings.forEach(booking => {
allSlots = allSlots.filter(slot => {
return booking.date === slot.date && booking.time !== slot.time;
});
});
Edit: You will have to scope allSlots with let instead of const for this to work. You could also assign allSlots to another variable if you want to keep allSlots in tact:
let slots = allSlots;
existingBookings.forEach(booking => {
slots = slots.filter(slot => {
return booking.date === slot.date && booking.time !== slot.time;
});
});

Why Isnt My Array (Based On Time) Being Ascendency Sorted?

I have this script here
let myVar = [{time: "3:00 pm", name: "Landon"},{time: "5:20 pm", name: "Amanda"},{time: "4:00 pm", name: "Kid"}]
const sortedArray = myVar.sort((a,b) => new moment(a.time).format('hh:mm a') - new moment(b.time).format('hh:mm a'))
console.log(sortedArray)
The idea is that we sort the array by time. But its not working and Im not sure why.
Every google search leads me to answers like this: https://gist.github.com/onildoaguiar/6cf7dbf9e0f0b8684eb5b0977b40c5ad
But it does not work for me.
Your code passes a format at the wrong moment. You need to specify the input format, not the output format.
So change to:
let myVar = [{time: "3:00 pm", name: "Landon"},{time: "5:20 pm", name: "Amanda"},{time: "4:00 pm", name: "Kid"}]
const sortedArray = myVar.sort((a,b) => new moment(a.time, 'hh:mm a') - new moment(b.time, 'hh:mm a'))
console.log(sortedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js" ></script>

Filtering unix timestamps

So, I am working on a time registration management tool. I have a date picker component where I choose the date I want to see the registrations from. It gives me the Unix timestamp of that day and I store that value, fx. 1606856503.
Now, I am retrieving all registrations from the API, which is an array of objects where each object is a registration. Each registration has a date property, which is basically a Unix timestamp from the date it was created.
[{
"id": "1",
"userId": "userId 1",
"customerId": "customerId 1",
"case": "case 1",
"description": "description 1",
"hours": 72,
"date": 1606826246,
"customer": "customer 1",
"project": "project 1"
}]
Now, that I have a date picker Unix timestamp, I would like to filter the registrations in order to filter and display only registrations which were made on the day of the Unix timestamp from the picker, but can't figure out how would I compare them and filter based on the day.
Here's a quick snippet illustrating using either Date.prototype.toISOString() or Date.prototype.toDateString() to filter against a specified timestamp.
Since your timestamps are stored in seconds and javascript dates use milliseconds, you need to multiply by 1000 when creating your dates
const filterTimestamp = 1606859476; // Tuesday, December 1, 2020 9:51:16 PM
const filterDate = new Date(filterTimestamp*1000);
You can then filter by comparing the first 10 characters of the date strings returned by toISOString() which will always keep the timezone as zero UTC offset
const filterDateString = new Date(filterTimestamp*1000).toISOString().slice(0, 10);
// "2020-12-01" sliced from "2020-12-01T21:51:16.000Z"
const regsOnDate = regs.filter(o => (
new Date(o.date*1000).toISOString().slice(0, 10) === filterDateString));
or by the date strings returned by toDateString() which will use the local timezone
const filterDateString = new Date(filterTimestamp*1000).toDateString();
const regsOnDate = regs.filter(o => (
new Date(o.date*1000).toDateString() === filterDateString));
// eg: compares "Mon Nov 02 2020" to "Tue Dec 01 2020"
Using toISOString()
const regs = [
{
"id": "1",
"date": 1606826246, // Tuesday, December 1, 2020 12:37:26 PM
"customer": "customer 1",
},
{
"id": "2",
"date": 1604353553, // Monday, November 2, 2020 9:45:53 PM
"customer": "customer 2",
},
{
"id": "3",
"date": 1606860022, // Tuesday, December 1, 2020 10:00:22 PM
"customer": "customer 3",
}
]
const filterTimestamp = 1606859476; // Tuesday, December 1, 2020 9:51:16 PM
const filterDateString = new Date(filterTimestamp*1000).toISOString().slice(0, 10);
// "2020-12-01" sliced from "2020-12-01T21:51:16.000Z"
const regsOnDate = regs.filter(o => (
new Date(o.date*1000).toISOString().slice(0, 10) === filterDateString));
console.log( regsOnDate );
Using toDateString()
const regs = [
{
"id": "1",
"date": 1606826246, // Tuesday, December 1, 2020 12:37:26 PM
"customer": "customer 1",
},
{
"id": "2",
"date": 1604353553, // Monday, November 2, 2020 9:45:53 PM
"customer": "customer 2",
},
{
"id": "3",
"date": 1606860022, // Tuesday, December 1, 2020 10:00:22 PM
"customer": "customer 3",
}
]
const filterTimestamp = 1606859476; // Tuesday, December 1, 2020 9:51:16 PM
const filterDateString = new Date(filterTimestamp*1000).toDateString();
const regsOnDate = regs.filter(o => (
new Date(o.date*1000).toDateString() === filterDateString));
console.log( regsOnDate );
UNIX timestamps are seconds since 1 Jan 1970 UTC, ECMAScript time values are milliseconds since the same epoch, see Convert a Unix timestamp to time in JavaScript.
If you just want to compare values for the same date UTC, you can just compare whole days since the epoch. That means a simple arithmetic operation on the value rather than using Date objects. e.g.
let data = [{"id": "1","date": 1606826246}, // 1 Dec 2020 UTC
{"id": "2","date": 1606867200}, // 2 Dec 2020 UTC
{"id": "3","date": 1606953600} // 3 Dec 2020 UTC
];
// Start with date sometime on 2 Dec 2020 UTC
let d = new Date(Date.UTC(2020,11,2,8,32,21)); // 2 Dec 2020 08:32:21 Z
console.log('Test date: ' + d.toISOString());
// Get whole days since epoch
let daysSinceEpoch = d.getTime() / 8.64e7 | 0;
console.log('daysSinceEpoch: ' + daysSinceEpoch);
// Find matching records in data
let result = data.filter(obj => (obj.date / 8.64e4 | 0) == daysSinceEpoch);
console.log('Matching records: ' + JSON.stringify(result));
// Matching date values
console.log('Matching dates:');
result.forEach(obj => console.log('id: ' + obj.id + ' on ' + new Date(obj.date * 1000).toISOString().substr(0,10)));
You can do the same thing with local dates, you just need to be a bit more careful of getting the days, see How do I get the number of days between two dates in JavaScript?

jQuery Add Array Values

I have a json given below
0 : {car_rental_id: "6007", sharing_schedule: "9:00 AM", booked_cars: '1', woo_order_id: "6421", woo_status: "on-hold" }
1 : {car_rental_id: "6007", sharing_schedule: "9:00 AM", booked_cars: '3', woo_order_id: "6424", woo_status: "pending" }
2 : {car_rental_id: "6007", sharing_schedule: "10:00 AM", booked_cars: '5', woo_order_id: "6427", woo_status: "pending"}
The goal here is to get the total number of booked_cars on a time. So according to this json. I should get
4 bookings for 9:00 AM and 5 bookings for 10:00 AM.
How do I achieve that?
var test = [{
car_rental_id: "6007",
sharing_schedule: "9:00 AM",
woo_order_id: "6421",
woo_status: "on-hold",
booked_cars: '1'
}, {
car_rental_id: "6007",
sharing_schedule: "9:00 AM",
woo_order_id: "6424",
woo_status: "pending",
booked_cars: '3'
}, {
car_rental_id: "6007",
sharing_schedule: "10:00 AM",
woo_order_id: "6427",
woo_status: "pending",
booked_cars: '5'
}];
var carsBookedByTime = test.reduce(function(collection, element){
var bookedCars = parseInt(element.booked_cars);
//initialize total in the collection if it does not exist
if (!collection[element.sharing_schedule]) collection[element.sharing_schedule] = 0;
collection[element.sharing_schedule] += bookedCars;
return collection;
}, {});
console.log(carsBookedByTime);
You could change it to something like that.
var values = window.confirmedBookings.reduce(function(prev, current) {
if(!prev[current.sharing_schedule]) prev[current.sharing_schedule] = 0;
prev[current.sharing_schedule] += Number(current.booked_cars);
return prev;
}, {})
#edit: updated an answer to fit a question.
You appear to be asking for :
window.totalBooked = {};
$.each(window.confirmedBookings, function(index, value) {
console.log(value.booked_cars);
window.totalBooked[value.sharing_schedule] = (window.totalBooked[value.sharing_schedule] || 0) + +value.booked_cars;
});
or, slightly simpler :
window.totalBooked = window.confirmedBookings.reduce(function(obj, value) {
obj[value.sharing_schedule] = (obj[value.sharing_schedule] || 0) + +value.booked_cars;
return obj;
}, {});
DEMO

How to merge days with similar opening hours

I'm trying to write a javascript function to merge days with similar opening hours of a store together. For example, if we have:
"hours": [
"Friday 11:00am - 3:00pm, 5:00pm - 10:00pm",
"Monday 11:00am - 3:00pm, 5:00pm - 9:30pm",
"Saturday 12:00pm - 10:00pm",
"Sunday 12:00pm - 9:30pm",
"Thursday 11:00am - 3:00pm, 5:00pm - 9:30pm",
"Tuesday 11:00am - 3:00pm, 5:00pm - 9:30pm",
"Wednesday 11:00am - 3:00pm, 5:00pm - 9:30pm"
],
I want the code to simplify it to:
"hours": [
"Mo-Sa 11:00-14:30",
"Mo-Th 17:00-21:30",
"Fr-Sa 17:00-22:00"
],
Is there a way of accomplishing this without a long list of if/else or case statements?
Go functional and save a lot of mess.
Assuming that this is your data:
var data = [
{day: "Mon", open: 900, close: 1700},
{day: "Tue", open: 900, close: 1700},
{day: "Wed", open: 700, close: 1700},
{day: "Thu", open: 900, close: 1700},
{day: "Fri", open: 900, close: 1700},
{day: "Sat", open: 900, close: 1900},
{day: "Sun", open: 900, close: 1900},
];
You can simply reduce the array to a merged array in 6 lines of code:
var merged = data.reduce(function(preVal, curVal) {
var last = preVal[preVal.length - 1];
if (last && last.open == curVal.open && last.close == curVal.close) {
last.endDay = curVal.day;
} else {
preVal.push(curVal);
}
return preVal;
}, []);
And just in case for debugging:
for (var i in merged) {
var m = merged[i];
var endDay = m.endDay ? " to " + m.endDay : "";
console.log(m.day + endDay + " " + m.open + "-" + m.close);
}
BONUS Now, if you have to convert merged into a different format (e.g., something that you need to print on the screen) you can go functional again and map the merged into whatever format you want:
var mergedNewFormat = merged.map(function(v) {
return {
days: [v.day, v.endDay ? v.endDay : v.day],
hours: [v.open, v.close],
};
});
I would suggest breaking your data down into a more structured format than what you currently have specified in your comments such as:
var data = [
{ day: "Mon", hours: "11:00 AM to 10:30 PM" },
{ day: "Thu", hours: "11:00 AM to 10:30 PM" },
{ day: "Tue", hours: "11:00 AM to 10:30 PM" },
{ day: "Wed", hours: "11:00 AM to 10:32 PM" },
{ day: "Fri", hours: "11:00 AM to 10:00 PM" },
{ day: "Sat", hours: "11:00 AM to 10:00 PM" },
{ day: "Sun", hours: "11:00 AM to 10:30 PM" }
];
Now you can iterate over the days and group by identical hours like this:
function collapseHours(data) {
var collapsed = [];
var idx = -1;
for(var i=0; i<data.length; i++) {
var day = data[i];
if(idx == -1 || collapsed[idx].hours != day.hours) {
collapsed.push({days:[day.day],hours:day.hours});
idx++;
} else {
collapsed[idx].days.push(day.day);
}
}
return collapsed;
}
This collapseHours(data) would produce the following:
[
{"days":["Mon","Thu","Tue"],"hours":"11:00 AM to 10:30 PM"},
{"days":["Wed"],"hours":"11:00 AM to 10:32 PM"},
{"days":["Fri","Sat"],"hours":"11:00 AM to 10:00 PM"},
{"days":["Sun"],"hours":"11:00 AM to 10:30 PM"}
];
Now you can pretty print your hours like this:
function prettyPrintHours(collapsed) {
var lines = [];
for(var i=0; i<collapsed.length; i++) {
var line = collapsed[i];
var days = line.days;
if(days.length == 1) {
lines.push(days[0]+" "+line.hours);
} else {
lines.push(days[0]+"-"+days[days.length-1]+" "+line.hours);
}
}
return lines;
}
Which will produce:
[
"Mon-Tue 11:00 AM to 10:30 PM",
"Wed 11:00 AM to 10:32 PM",
"Fri-Sat 11:00 AM to 10:00 PM",
"Sun 11:00 AM to 10:30 PM"
]
Given these two functions it should be relatively simple to customize the data format and output formatting to your exact needs.

Categories