Using javascript create inner array group by month and year - javascript

I have an array look like:
var v = ["07/27/2015", "07/28/2015", "08/29/2015", "08/29/2015", "07/27/2016"]
What I want to do is sort this dynamically into a new empty array nv. When the sorting is done nv should look like.
var nv = [["07/27/2015", "07/28/2015"], ["08/29/2015", "08/29/2015"], ["07/27/2016"]]
Is it possible to sort like this way?

var dates = ["07/27/2015", "07/28/2015", "08/29/2015", "08/29/2015", "07/27/2016"];
var groupedDates = dates.reduce(function(l, r) {
var keyParts = r.split("/"),
key = keyParts[2] + keyParts[0];
if (typeof l[key] === "undefined") {
l[key] = [];
}
l[key].push(r);
return l;
}, {});
var result = Object.keys(groupedDates)
.sort(function(a, b) { return Number(a) - Number(b); })
.map(function(key) {
return groupedDates[key];
});
console.log(result); // [["07/27/2015","07/28/2015"],["08/29/2015","08/29/2015"],["07/27/2016"]]
fiddle

So I made a function that puts the dates into an object whose properties are month and year. A date is put into the property of its month and year. The function then creates an array and creates an inner array for every property of the function. In each inner array it puts all the dates of that property. I figured this approach would be more efficient than nested for loops.
// function takes an array of dates in the following format MM/DD/YYYY
// outputs an array with inner arrays of dates. Each inner array contains dates of the same month and year
var groupDates = function(dateArray) {
// create object to organize dates by month and year
var dateHash = {};
// the array that is outputted
var groupedDates = [];
//for every date in dateArray
dateArray.forEach(function(currentDate) {
// check if any other dates with the same month and year exist in the dateHash object
if (dateHash[currentDate.substr(0, 2) + currentDate.substr(6)]) {
// if other dates exist, push the date to the array in the dateHash property for the dates current month and year
dateHash[currentDate.substr(0, 2) + currentDate.substr(6)].push(currentDate);
} else {
// otherwise create a property for the dates month and year and store the current date in an array in the propery
dateHash[currentDate.substr(0, 2) + currentDate.substr(6)] = [currentDate];
}
});
// for every propery in the datehash, push the array of dates into the grouped dates array
for (var dateGroup in dateHash) {
groupedDates.push(dateHash[dateGroup]);
}
return groupedDates;
};
var dateArray = ["07/27/2015", "07/28/2015", "08/29/2015", "08/29/2015", "07/27/2016"];
console.log(groupDates(dateArray));

You can loop over the array and check for each value if it has a new month and year, or it's already included in the sorted array. I think like this untested code:
new_arr = new Array();
for(var i=0; i < v.length; i++){
var this_date = new Date(v[i]);
var month_and_year = this_date.getMonth() + this_date.getFullYear();
if(typeof(new_arr[month_and_year]) == 'undefined'){
new_arr[month_and_year] = new Array();
}
new_arr[month_and_year].push(v[i])
}

Related

Return index of matched array not working - Javascript Google Apps Script

I have a spreadsheet and row #1 has dates in each cell going across
I want to return the column number whenever that column matches today's date. First header starts in cell B1.
I am using the following and I can get it to work, but when instead I do 'return i', it always returns '0'.
function getColumnIndex() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var lastColumn = sheet.getLastColumn();
var data = sheet.getRange(1,2,1,lastColumn).getValues(); //create an array of data from row 1
for (var i = 0; i <= data.length; i++) {
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
if (data[i] == dateToday) {break};
{
return i;
}
}
}
Now if I switch the last line 'return i' to 'return dateToday' the function will work and it will return the correct date so I know it's matching properly (and if I change row cells to other values it will return those values if it matches). I just can't get it to spit out the index number when I put 'return i'.
Issues / Explanation:
var data = sheet.getRange(1,2,1,lastColumn).getValues(); returns a 2D array.
As a result, data[i] returns a 1D array which is actually referring to the row. To solve this issue, flatten the array to convert it to 1D:
var data = sheet.getRange(1,2,1,lastColumn).getDisplayValues().flat();
Your if condition is executed at the first iteration i=0 because you put a semicolon ; right after it. Also, break is not needed because nothing will be executed after the return statement:
Replace:
if (data[i] == dateToday) {break};
{
return i;
}
with
if (data[i] == dateToday)
{
return i;
}
When you are working with date comparisons, you need to use getDisplayValues() to be sure that you are comparing the the displayed values
and not the value of the date.
Solution:
function getColumnIndex() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var lastColumn = sheet.getLastColumn();
var data = sheet.getRange(1,2,1,lastColumn).getDisplayValues().flat(); //create an array of data from row 1
for (var i = 0; i <= data.length; i++) {
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
if (data[i] == dateToday)
{
return i;
// return i+2; // if you want to get the column number instead.
}
}
}
Keep in mind, i refers to the position of the array. In JavaScript, the indexes in the arrays start from 0. Also, your data starts from the second column. If you want your script to return the number of column, then change return i to return i+2.
function getColumnIndexForToday() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getActiveSheet();
const shsc=2;
const offset=0;//0 if you want the index from column B 1 if you want the index from ColumnA
const data=sh.getRange(1,shsc,1,sh.getLastColumn()-shsc+1).getDisplayValues()[0];//assuming format is "MM/dd/yyyy"
var dObj={};
data.forEach(function(h,i){dObj[h]=i+offset;});//You really can just do this once and then use it repeatedly
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
return dObj[Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"MM/dd/yyyy")];
}

Get the next highest date value after excluding values from an array

I have a myDate variable with the value 18-Nov-2013.Each day its value is being changed.Tommorow this myDate variable will have the value 19-Nov-2013.I have a list of values that i have mapped into a single array named exclude which contains some dates that are to be excluded ,now it has values ["20-Nov-2013",21-Nov-2013", "23-Nov-2010"] .How could i filter my value from the list of values from the exclude array.I need the next highest value from the array.So here i need the value 22-Nov-2013 after tommorrows date.Could someone help me with this.
var excluded = ["30-Nov-2013","01-Dec-2013","02-Dec-2013"];
var myDate = "29-Nov-2013";
var month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var current = new Date(myDate);
while(true){
current = new Date((current.getDate()+1<10? "0"+(current.getDate()+1):(current.getDate()+1))+ "-" + month[current.getMonth()] + "-" + current.getFullYear());
var checkDate = (current.getDate()<10? "0"+(current.getDate()):(current.getDate()))+ "-" + month[current.getMonth()] + "-" + current.getFullYear();//this is necessary for when the +1 on day of month passes the month barrier
if(-1 == excluded.indexOf(checkDate))
break;
}
alert(checkDate);
I don't know if this is the best approach, or if is the best algorithm, but you may try this:
var myDate = ["17-Nov-2013", "18-Nov-2013"];
var excluded = ["20-Nov-2013", "21-Nov-2013", "23-Nov-2013"];
var months = {"Nov": 10}; // Add others months "Jan": 1, "Fev": 2 etc...
function findExcluded(date)
{
for (var i = 0; i < excluded.length; i++)
{
if (excluded[i] === date)
{
return true;
}
}
return false;
}
function nextDate()
{
var last = myDate[(myDate.length - 1)];
var s = last.split("-");
var d = new Date(s[2], months[s[1]], s[0]);
var next = new Date(d);
var chkDate = "";
do
{
next.setDate(next.getDate() + 1);
chkDate = next.getDate() + "-" + findMonth(next.getMonth()) + "-" + next.getFullYear();
} while(findExcluded(chkDate));
return chkDate;
}
function findMonth(m)
{
var i = 10; // When you fill all months on 'months' array, this variable should start at '0' in order to loop to works.
for (var month in months)
{
if (i == m)
{
return month;
}
i++;
}
}
var nd = nextDate();
alert(nd);
See it woring here.
No code ? Well here will be my method:
1.Get next date for mydate. Say that is var nextDate.
2.Check whether that date exist in the array.
3.If exists add one more day to nextDate. Again check in the array.
4.Do it until you get a date which is not present in your exclude array
For checking whether it exists in the array you can use arrValues.indexOf(nextDateInProperFormat) > -1

How to sort just a single column in 2d array

I have a 2d array called dateTime[]. dateTime[count][0] contains future datetime and dateTime[count][1] contains a 4 digit value like 1234 or something.
I am trying to sort the column 0 that is dateTime[count][0] in ascending order. ( i,e, sorting the colunm 0 of the 2d array according to closest datetime from now)
Suppose my javascript 2d array is like:
dateTime[0][0] = 2/26/2013 11:41AM; dateTime[0][1] = 1234;
dateTime[1][0] = 2/26/2013 10:41PM; dateTime[1][1] = 4567;
dateTime[2][0] = 2/26/2013 8:41AM; dateTime[2][1] = 7891;
dateTime[3][0] = 3/26/2013 8:41AM; dateTime[3][1] = 2345;
I just wrote like this actually this is how I inserted value to dateTime[count][0] ; = new Date(x*1000); where x is unix time()
How I want the array to look after sorting:
dateTime[0][0] = 2/26/2013 8:41AM; dateTime[0][1] = 7891;
dateTime[1][0] = 2/26/2013 11:41AM; dateTime[1][0] = 1234;
dateTime[2][0] = 2/26/2013 10:41PM; dateTime[2][1] = 4567;
dateTime[3][0] = 3/26/2013 8:41AM; dateTime[3][1] = 2345;
please let me know how to solve this with less code.
Thanks. :)
This what I have done till now (I haven't sorted the array, also here dateTime is called timers)
function checkConfirm() {
var temp = timers[0][0];
var timeDiv = timers[0][1];
for (var i=0;i<timers.length;i++) {
if (timers[i][0] <= temp) { temp = timers[i][0]; timeDiv = timers[i][1]; }
}
if (timers.length > 0 ){ candidate(temp,timeDiv); }
}
function candidate(x,y) {
setInterval(function () {
var theDate = new Date(x*1000);
var now = new Date();
if ( (now.getFullYear() === theDate.getFullYear()) && (now.getMonth() === theDate.getMonth()) ) {
if ( (now.getDate() === theDate.getDate()) && (now.getHours() === theDate.getHours()) ) {
if ( now.getMinutes() === theDate.getMinutes() && (now.getSeconds() === theDate.getSeconds()) ) { alert("its time"); }
}
}
}, 10);
}
AT the end, I wanted to alert the user every time when the current time matches the time in the array. This is how I tried to solve the problem but this is completely wrong approach.
Use the .sort() function, and compare the dates.
// dateTime is the array we want to sort
dateTime.sort(function(a,b){
// each value in this array is an array
// the 0th position has what we want to sort on
// Date objects are represented as a timestamp when converted to numbers
return a[0] - b[0];
});
DEMO: http://jsfiddle.net/Ff3pd/

datepicker with unavailable date from/until

I have an array of unavailable dates set at unavailableDates and weekends.
Array:
<script type="text/javascript">//<![CDATA[
var unavailableDates = [];
{foreach $fixed.rows as $row}
var row = {};
row['date_from'] = "{$row.fixed_date_from.value}";
row['date_until'] = "{$row.fixed_date_until.value}";
row['name'] = "{$row.fixed_name.value} ({$row.fixed_type.value})";
unavailableDates.push(row);
{/foreach}
//]]></script>
Q1) How can I add an extra check for the until date. I have got it working as shown below for the from date?
Q2) Can I improve the code to use in_array instead of loop through each of the dates for each calendar day?
var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"];
var unavailableDays = ["Saturday","Sunday"];
$("#.datePicker").datepicker($.extend(true, {}, $.initDatePickers.defaults, {
beforeShowDay: function(date) {
ymd = date.getFullYear() + "-" + ("0"+(date.getMonth()+1)).slice(-2) + "-" + ("0"+date.getDate()).slice(-2);
day = new Date(ymd).getDay();
result = null;
// Check if date in unavailable array or weekend
for(var i = 0; i < unavailableDates.length; i++){
if ((ymd == unavailableDates[i].date_from) && $.inArray(days[day], unavailableDays) < 0) {
return [false,"unavailable",unavailableDates[i].name];
}
}
if(result){
return result;
} else {
return [true, "available", ""];
}
}
}));
Use the befreShowDay option to parse your data array to determine if day is selectable or not
beforeShowDayType: Function( Date date )
A function takes a date as a parameter and must return an array with [0] equal to true/false indicating whether or not this date is selectable, 1 equal to a CSS class name or "" for the default presentation, and [2] an optional popup tooltip for this date. It is called for each day in the datepicker before it is displayed.

Count duplicate dates in list and occurance of duplicate dates in count

I am having list of dates in which i need to check for duplicates and occurances of duplicate dates in count i need to implement in javascript...
Try to help me out
thank in advance.
EX: { 12/11/2011, 12/11/2011, 11/4/2012, 12/6/2012, 12/6/2012, 12/6/2012}
Desire output: {12/11/2011, 11/4/2012, 12/6/2012}
count: 12/11/2011 =2
count: 12/6/2012 =3
Use Underscore.js
_.reduce(list, iterator, memo, [context]) Aliases: inject, foldl Also known as inject and foldl, reduce boils down a list of values into a
single value. Memo is the initial state of the reduction, and each
successive step of it should be returned by iterator.
Example:
var dates = [ '1/1/2006', '1/1/2006', '1/1/2007', '1/1/2007', '1/1/2007', '1/1/2006', '1/1/2012', '1/1/2006', '1/1/2009', '1/1/2012'];
var x = _.reduce(dates,
function(counts, date) {
counts[date] = (counts[date] || 0) + 1;
return counts;
}, {});
alert(JSON.stringify(x));
Produces
{"1/1/2006":4,"1/1/2007":3,"1/1/2012":2,"1/1/2009":1}
​
If your dates are strings (stored as a string) you can try something like this:
var dates = ["12/11/2011", "12/11/2011", "11/4/2012", "12/6/2012", "12/6/2012", "12/6/2012"];
var dates_set = {}; // key will be date, and values will be count
for (var i = dates.length - 1; i >= 0; i--) {
var d = dates[i];
if (dates_set.hasOwnProperty(d)) { // already is in our set, just increase counter
dates_set[d] = dates_set[d] + 1;;
} else { // there is no such date, lets add it
dates_set[d] = 1
}
};
document.write(dates_set["12/11/2011"]);
document.write("<br />");
document.write(dates_set["12/6/2012"]);

Categories

Resources