I am writing a function that takes an array of objects and parses the data into a date range. Right now I have the following:
function(result) {
var dates = [];
var data = [];
for (var i = 0; i < result.length; i++) {
var story = result[i];
var date = new Date(parseInt(story['UpdatedAt'].replace("/Date(", "").replace(")/", ""), 10));
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
var estimate = story['Estimate'];
if (estimate == null)
estimate = 0;
if (dates[date] == null) {
dates[date] = [date, 1, estimate];
data.push(dates[date]);
} else {
dates[date][1] += 1;
dates[date][2] += estimate;
data.push(dates[date]);
}
}
console.log(dates);
drawStoriesCompletedChart(data);
}
I have two arrays, one for dates and one for data. The result of this function is fed into the Google Charts API, which requires the data to be [[a,b,c], [a,b,c]]
The code above works thanks to the way Google Charts works, but I do know that since the data array is being pushed to every single loop iteration, there will be a bunch of duplicates without updated data.
What I want is take the data from each object and parse it so it is like the following:
[[Date, Total Stories, Total Estimate], [...]] and have nothing else in the object.
Related
I am trying to split day from full-date and calculating the range between them and inserting them into a array to add that to a database.
<script>
function()
{
var sd = "26-04-2020";
var a = sd.split("-");
var ed = "28-04-2020";
var b = ed.split("-");
var p1= a[1];
var p2= a[2];
var p3= a[3];
var q1= b[1];
var q2= b[2];
var q3= b[3];
var datearry = [];
if( p1<q1 && p2=q2 && p3=q3)
{
for (i=p1; i<q1; i++)
{
datearry = ("i"+"p2"+"p3");
}
}
else if( p1<q1 && p2<q2 && p3=q3)
{
for (i=p1; i<q1; i++)
{
for (j=p2; j<q2; j++)
{
datearry = ("i"+"j"+"p3");
}
}
}
else if( p1<q1 && p2<q2 && p3<q3)
{
for (i=p1; i<q1; i++)
{
for (j=p2; j<q2; j++)
{
for (k=p3; k<q3; k++)
{
datearry = ("i"+"j"+"k");
}
}
}
}
alert(datearry);
}
</Script>
I did not get the expected result, anyone please give some suggestions or even code that works thankyou.
Your code has a number of issues:
function()
{
Is a syntax error, function declarations require a function name.
datearry = ("i"+"p2"+"p3");
datearray is initialised as an array, but here a string literal is assigned (literally "ip2p3"). You probably meant:
datearray.push(String(i) + p3 + p3);
which will add a string like "26042020" the first time, however as the algorithm progresses and the strings are turned into numbers, you'll start to get values like "152020" for 1 March 2020. So you need some padding, and probably a delimiter, to get "01-05-2020" and match the input format.
Lastly, the code doesn't seem to correctly accommodate transitions over month and year boundaries. Fixing that really isn't useful as it's much more complex than it needs to be or I'm prepared to bother with given there are much simpler alternatives. :-)
If you're looking for an array of timestamps between two dates, one strategy is to convert the timestamps to dates, then loop over the required range storing the required output timestamps in an array.
Existing questions deal with how to parse a date string and how to format a date. You can put those together to create a function something like the following:
// startDate, endDate in format dd-mm-yyyy
// Return array of dates inclusive of start and end in same format
function getDateRange(startDate, endDate) {
// Parse dd-mm-yyyy
let qParse = s => {
let [d, m, y] = s.split(/\D/);
return new Date(y, m-1, d);
};
// Format date as dd-mm-yyyy
let qFormat = d => {
let z = n => (n<10? '0' : '') + n;
return z(d.getDate())+'-'+z(d.getMonth()+1)+'-'+d.getFullYear();
}
// Setup for loop
let start = qParse(startDate);
let end = qParse(endDate);
let result = [];
// Loop from start to end, incrementing
// the start date and writing to result array
do {
result.push(qFormat(start));
start.setDate(start.getDate() + 1);
} while (start <= end)
return result;
}
console.log(getDateRange('26-02-2020','03-03-2020'));
// Different delimiters in input
console.log(getDateRange('28.12.2020','03/01/2021'));
You should also validate the input. The parse and format functions are closed in the function as they're only designed to work with the specific format of the OP (i.e. they aren't general parsing or formatting functions).
I have a script that runs in a google sheet that parses emails and creates new lines in the sheet. This is used to create a log file from periodically emailed log updates. This works very well.
Currently, I have a variable that is used to determine which emails are ingested based on the month (0=January, etc.)
That variable has to be adjusted every month and then I have to create a new monthly sheet (tab in the main) and do a bunch of sorting and moving emails in gmail.
I'd like to set this up so it automatically puts the January emails in a sheet for January and the February emails in a sheet for February.
I thought about cascading if elseif statements, but that got too unwieldy fast.
I thought about iterating using a for loop through an array holding all emails, but that seems convoluted too.
Any suggestions?
::EDIT::
To be clear, I'm really interested in how to parse all of the emails and send the ones from January to the January sheet (for example).
::EDIT:: Added current script
function myFunction() {
var label = GmailApp.getUserLabelByName(myLabel);
var label2 = GmailApp.getUserLabelByName(newLabel);
var threads = label.getThreads();
var data = new Array();
var newData = new Array();
// get all the email threads matching myLabel
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
// archive thread
label2.addToThread(threads[i]);
label.removeFromThread(threads[i]);
// get each individual email from the threads
for (var j = 0; j < messages.length; j++) {
var bodyText = messages[j].getPlainBody();
// split the email body into individual "paragraph" strings based on the regExp variable
while (matches = regExp.exec(bodyText)) {
var logdata = matches[1];
for (k in keys) {
logdata = logdata.replace(keys[k], "");
}
// split out each "paragraph" string into an array
var lines = logdata.split(/[\r\n]+/);
for (l in lines) {
lines[l] = lines[l].replace('*F','');
lines[l] = lines[l].trim();
}
for (l in lines) {
lines[l] = lines[l].replace(/^(\:\s)/, "");
}
// Turn the first element in the array into a date element, format it, and put it back
lines[0] = Utilities.formatDate(new Date(lines[0]), "America/Phoenix", "M/d/yy HH:mm:ss");
// Put the array to a new item in the data array for further processing
if (curMonth == (new Date(lines[0]).getMonth())) {
data.push(lines);
}
}
}
}
// Compare the information in the data array to oldData information in the sheet
if (data.length) {
var oldData = s.getRange(range).getValues();
for (h in oldData) {
oldData[h][0] = Utilities.formatDate(new Date(oldData[h][0]), "America/Phoenix", "M/d/yy HH:mm:ss");
}
for (i in data) {
var row = data[i];
var duplicate = false;
for (j in oldData) {
if (row.join() == oldData[j].join()) {
duplicate = true;
}
}
if (!duplicate) {
newData.push(row);
}
}
// check to write newData only if there is newData, this stops an error when newData is empty
if (newData.length) {
s.getRange(s.getLastRow() + 1, 1, newData.length, newData[0].length).setValues(newData);
}
s.getRange(range).sort(1); //sorts the sheet
}
}
Try this:
function getSheet(date) {
var ss=SpreadsheetApp.openById('SpreadsheetId');
var name=Utilities.formatDate(new Date(date), Session.getScriptTimeZone(), "MMMyyyy")
var sh=ss.getSheetByName(name);
if(!sh) {
var sh=ss.insertSheet(name);
}
return sh;
}
I ended up basing my solution on the solution that #cooper provided, but had to go a little further.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var month = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
var curMonth = new Date().getMonth(); //number of month -1 aka: January = 0
var sheetname = month[curMonth] + " " + new Date().getYear();
var s = ss.getSheetByName(sheetname);
function newMonth(){
if (!s) {
var template = ss.getSheetByName('Template').copyTo(ss);
template.setName(sheetname);
s = ss.getSheetByName(sheetname); //"reload" the sheet
s.showSheet(); //unhide the new copy since 'Template' is hidden in the spreadsheet
ss.setActiveSheet(s); //make it active
ss.moveActiveSheet(0); //move it to the first position
}
}
Currently working on an application which requires to display a set of values in different currencies. This is part of an application but everything I provide here should be enough as this is the main section I am working with. I have a json file which is read in and it is stored into an array called valuesArray, this array has all the information, such as the amount, currency, etc. With the currencies being sorted with highest first to the lowest on display like this:
EUR 500.00
USD 200.00
This is the code that I have created but it seems like this wouldn't be effective the more currencies I have. I've just put an array declaration above the function but just above this function is where I do all the json stuff and adding it into the array. $scope.valuesArray has data at this point.
$scope.valuesArray =[];
$scope.total = function()
{
var eur_total = 0;
var usd_total = 0;
if (typeof $scope.valuesArray != 'undefined')
{
var length = $scope.valuesArray.length;
for (var i = 0; i<length ; i++)
{
switch($scope.valuesArray[i].currency)
{
case "USD":
usd_total += parseFloat($scope.valuesArray[i].value);
break;
default:
eur_total += parseFloat($scope.valuesArray[i].value);
break;
}
}
}
var cost_total= [usd_total,eur_total];
total.sort(function(a, b){return b-a});
return format_to_decimal(total[0]) + "\x0A" + format_to_decimal(total[1]);
}
In my for loop I go through every single data in the array and break each currency down within the switch statement and finding the total amount of each currencies.
The last bit is kind of temporary as I couldn't figure out a different way of how to do it. I sort the totals for the currencies I have from the highest at the top.
I return the function with a function call for format_numeric_with_commas which gives me the value in proper currency format and this displays the value. Will update this and add that code when I get to it. But I have used the indexes as a rough logic to show what I want to get out of it. So in this case, total[0] should be 500.00 and total[1] should be 200.00.
On top of this I want to be able to display the currency type for each. So like the example above.
You can try to save all the calculations in the array with currency index.
$scope.valuesArray = [];
$scope.total = function () {
var totalsArray = [];
if (typeof $scope.valuesArray != 'undefined') {
var length = $scope.valuesArray.length
for (var i = 0; i < length; i++) {
if (!totalsArray[$scope.valuesArray[i].currency]) {
totalsArray[$scope.valuesArray[i].currency] = 0;
}
totalsArray[$scope.valuesArray[i].currency] += $scope.valuesArray[i].value;
}
}
var cost_total = [];
for (var k in totalsArray) {
cost_total.push(currency:k,value:totalsArray[k]);
}
cost_total.sort(function (a, b) {
return b.value - a.value
});
return format_to_decimal(cost_total[0].value)+cost_total[0].currency + "\x0A" + format_to_decimal(cost_total[1].value);
I am building a small weather application, by using data from a weather API. I have to convert the temperature from kelvin to Celsius, and then use substring to get rid of all the decimals. However, sometimes the temperature is below 0 and even -10 Celsius, so i have to run through a for loop to make sure to get the same format every time (Max 1 decimal).
And now to my problem. I make an array that keeps all the temperatures in Celsius. Then i run through a loop to make sure to get the right format (-11.5, 1.9, 18.7....) Then i add it to a new array, and afterwards a json string. This whole thing works, but somehow i can't use $scope to send my data to the HTML file.
Any ideas of, what I am doing wrong?
success(function (data, status, headers, config) {
$scope.forecast = data;
//Creates array with temperatures
var arrayTemp = [
data.list[0].temp.day-273.15,
data.list[1].temp.day-273.15,
data.list[2].temp.day-273.15,
data.list[3].temp.day-273.15,
data.list[4].temp.day-273.15,
data.list[5].temp.day-273.15,
data.list[6].temp.day-273.15
];
//Function that takes array as parameter, and makes the right format
function add(array){
var newArray = [];
for (i = 0; i < array.length; i++) {
if (array[i] > 0) {
if (array[i] > 10) {
var res = array[i].toString().substring(0, 4)
} else {
var res = array[i].toString().substring(0, 3)
}
} else {
if (array[i] > -10) {
var res = array[i].toString().substring(0, 4)
} else {
var res = array[i].toString().substring(0, 5)
}
}
//Add data to new array
newArray.push(res);
}
//Creates json
var json = {"temps":{"one":newArray[0],"two":newArray[1],"three":newArray[2],"four":newArray[3],"five":newArray[4],"six":newArray[5],"seven":newArray[6]}};
return json;
}
var newJson = add(arrayTemp);
$scope.data = newJson;
}).
I would like to have an array with timestamp as keys and numbers as values. This way I want to track how many cars have entered or left a parking lot as well as how many cars have parked in the parking lot simultaneously.
Basics:
- Get the list of parking actions with enter date and exit date for each transaction
- Get all those dates into an array with timestamp as key and += 1 if enter date and -=1 for exit date
- Sort by date
- Go through sorted array and add to a counter, track if new maximum is reached
var result = [];
var counter = 0;
var max = 0;
//SELECT enterTS, exitTS FROM parking;
// validated, that works
while (!rs.eof) {
var es = rs.fields(1).toString();
var dd = rs.fields(2).toString();
result[es] += 1; //might happen at the same time with exit or other entries
result[dd] -= 1;
alert('Start' + es); //correct timestamp
alert('Array' + result[es]); //shows NaN
}
result.sort();
for (var key in result) {
counter += result[key];
if(counter > max){
max = counter;
}
}
Thanks for any help. I know this is not a working code snippet, but without the data connection this is tricky. I already tried the associative arrays, but was not able to understand how I can use in this example.
Thanks again,
fj
Use an object, not an array.
var result = {};
Now to fill it you can just:
result[es] = result[es] + 1 || 1
And your for...in loop should work (but you should use .hasOwnProperty for sanity's sake).
for (var key in result) {
if (result.hasOwnProperty(key)) {
counter += result[key];
if(counter > max){
max = counter;
}
}
}
Your NaN result comes because you are doing this:
result[es] += 1;
Since result[es] is undefined (because you never assigned it a value), undefined + 1 is NaN (not a number).
You can't use a string as an index into an array; it amounts to using the array as an object. Even if you could, the logic is wrong because sorting an array sorts the values, not the indexes.
I suggest that you create an array of parking event objects and sort that using a custom comparison function. Something like this (untested):
var result = [];
var counter = 0;
var max = 0;
//SELECT enterTS, exitTS FROM parking;
// validated, that works
while (!rs.eof) {
var es = rs.fields(1).toString();
var dd = rs.fields(2).toString(); // I'm assuming this is the exit time
// create two events: one for entry and one for exit
result.push({time: es, change: 1});
result.push({time: dd, change: -1});
}
// sort based on event time
result.sort(function(a, b){ return a.time.localeCompare(b.time); });
// scan events, tracking current parking population
for (var key in result) {
counter += result[key].change;
if(counter > max){
max = counter;
}
}