Apps Script, difficulty on trigger action when 2 values match [duplicate] - google-apps-script

I am getting this error:
"The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues."
in my Google Apps Script when I try to write an array of values to a sheet.
Below is a shortened (simplified) version of code. The actual code runs through about 10,000 records.
The error is generated in the last line, when the setValues is called.
I know I'm missing something super simple here.
function writeArrayToSheet() {
var ss = SpreadsheetApp.openById("Spreadsheet_ID");
var orderSheet = ss.getSheetByName("Sheet_Name");
var vTable = orderSheet.getRange(1,6,5,11).getValues(); //Raw data
var vWriteTable = []; //Data that will be written to sheet
var updateTime = new Date();
var i = 0;
var vSeconds = 0;
while (i < 5 && vTable[i][0] != "") {
//Logic section that calculated the number of seconds between
if (vSeconds == 0) {
vWriteTable.push("");
} else {
if (vTable[i][6] < certain logic) {
vWriteTable.push("Yes");
} else {
vWriteTable.push("");
}
}
i = i + 1;
} // End while
orderSheet.getRange(1,20,vWriteTable.length,1).setValues(vWriteTable);
} //End Function
This is what vWriteTable looks like when debugging:

setValues accepts(and getValues() returns):
1 argument of type:
Object[][] a two dimensional array of objects
It does NOT accept a 1 dimensional array. A range is always two dimensional, regardless of the range height or width or both.
If A1:A2 is the range, then corresponding values array would be like:
[[1],[3]]
Similarly, A1:B1 would be
[[1,2]]
A1:B2 would be
[[1,2],[3,4]]
Notice how the two dimension provides direction and that it is always a 2D array, even if the height or width of the range is just 1.
Solution:
Push a 1D array to make the output array 2D.
Snippet:
vWriteTable.push(/*Added []*/["Yes"]);
More information:
For a more detailed explanation of arrays in google sheets, checkout my answer here.

getValues returns object[rows][columns]
1 row object [[1...n]] - this maybe confusing b/c it may not look like 2D but it is 2D object[1 row][n columns]
2 row object [[1...n],[1...n]] - object[2 rows][n columns]
etc [[1...n],...,[1...n]] - etc
If you need to setValues to rectangular range with n rows and m columns, create EXACTLY n by m array 1st, then fill it with your values and send it to the MATCHING range in your spreadsheet. Here is some of my code that might help.
Getting values from 1st m cells in n-th row and pushing them in simple 1D array:
var arr = [];
var dataRow = sheet.getRange(n,1,1,m).getValues();
for (var j=0; j<dataRow.length; j++){
arr.push(dataRow[0][j]);
}
to replace them with new values from 1D array arr:
//create 2D array with just 1 row and m columns
var dataRow = new Array(1);
dataRow[0] = new Array(arr.length);
//fill it with values
for(var j=0;j<arr.length;j++){
dataRow[0][j]=arr[j];
}
//send it to the spreadsheet
sheet.getRange(n,1,1,arr.length).setValues(dataRow);

Related

How do I return: a nested value, that's inside multiple indecis, within a JSON.parse API, into my google sheet cells?

I'm fetching data from this binance API(https://api1.binance.com/api/v3/klines?symbol=ADAUSDT&interval=1d&limit=14).
I've, successfully, looped through the 'limit=14' parameter, which returns 0-13 indecis(or 14 indeces all together). These indeces contain various data on the pair specified in the 'symbol=ADAUSDT' parameter.
Now, theres 2 particular values I'm interested in: the high and the low of the day, which are in positions 2 and 3, respectively, in each index 0-13.
So, I've been able to log 0-13 results with the below script, but when I try to return the results to my sheet, it only populates the value in only one index, instead of 0-13.
How would I populate the results of my loop into the cells on my sheet?
function atrCalculation() {
var dailyHigh = UrlFetchApp.fetch("https://api1.binance.com/api/v3/klines?symbol=ADAUSDT&interval=1d&limit=14");
var jsonHighPrice = JSON.parse(dailyHigh);
for (var i = 0; i < jsonHighPrice.length; i++) {
data = jsonHighPrice[i];
Logger.log(data[2]);
Return data[i][2];
function in cell
only one value produced
Logger.log result
Thanks for any help!
You can simply retrieve all the data in your sheet 'klines' this way
function myKlines(){
var url='https://api1.binance.com/api/v3/klines?symbol=ADAUSDT&interval=1d&limit=14'
var source = UrlFetchApp.fetch(url).getContentText()
var json = JSON.parse(source)
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('klines')
sh.getRange(1, 1, json.length, json[0].length).setValues(json);
}

Receiving error The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues [duplicate]

I am getting this error:
"The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues."
in my Google Apps Script when I try to write an array of values to a sheet.
Below is a shortened (simplified) version of code. The actual code runs through about 10,000 records.
The error is generated in the last line, when the setValues is called.
I know I'm missing something super simple here.
function writeArrayToSheet() {
var ss = SpreadsheetApp.openById("Spreadsheet_ID");
var orderSheet = ss.getSheetByName("Sheet_Name");
var vTable = orderSheet.getRange(1,6,5,11).getValues(); //Raw data
var vWriteTable = []; //Data that will be written to sheet
var updateTime = new Date();
var i = 0;
var vSeconds = 0;
while (i < 5 && vTable[i][0] != "") {
//Logic section that calculated the number of seconds between
if (vSeconds == 0) {
vWriteTable.push("");
} else {
if (vTable[i][6] < certain logic) {
vWriteTable.push("Yes");
} else {
vWriteTable.push("");
}
}
i = i + 1;
} // End while
orderSheet.getRange(1,20,vWriteTable.length,1).setValues(vWriteTable);
} //End Function
This is what vWriteTable looks like when debugging:
setValues accepts(and getValues() returns):
1 argument of type:
Object[][] a two dimensional array of objects
It does NOT accept a 1 dimensional array. A range is always two dimensional, regardless of the range height or width or both.
If A1:A2 is the range, then corresponding values array would be like:
[[1],[3]]
Similarly, A1:B1 would be
[[1,2]]
A1:B2 would be
[[1,2],[3,4]]
Notice how the two dimension provides direction and that it is always a 2D array, even if the height or width of the range is just 1.
Solution:
Push a 1D array to make the output array 2D.
Snippet:
vWriteTable.push(/*Added []*/["Yes"]);
More information:
For a more detailed explanation of arrays in google sheets, checkout my answer here.
getValues returns object[rows][columns]
1 row object [[1...n]] - this maybe confusing b/c it may not look like 2D but it is 2D object[1 row][n columns]
2 row object [[1...n],[1...n]] - object[2 rows][n columns]
etc [[1...n],...,[1...n]] - etc
If you need to setValues to rectangular range with n rows and m columns, create EXACTLY n by m array 1st, then fill it with your values and send it to the MATCHING range in your spreadsheet. Here is some of my code that might help.
Getting values from 1st m cells in n-th row and pushing them in simple 1D array:
var arr = [];
var dataRow = sheet.getRange(n,1,1,m).getValues();
for (var j=0; j<dataRow.length; j++){
arr.push(dataRow[0][j]);
}
to replace them with new values from 1D array arr:
//create 2D array with just 1 row and m columns
var dataRow = new Array(1);
dataRow[0] = new Array(arr.length);
//fill it with values
for(var j=0;j<arr.length;j++){
dataRow[0][j]=arr[j];
}
//send it to the spreadsheet
sheet.getRange(n,1,1,arr.length).setValues(dataRow);

How can I shift rows by one when they match a substring?

Could someone please help me solve this?
Attached is the example sheet of what I am trying to do:
https://docs.google.com/spreadsheets/d/12w4rGArGi1I1wlpm5yJJtT5AAlMM4LcZC31_DpP6jZQ/edit?usp=sharing
I am trying to shift the rows that contain "PO" in my data selection. (see shift function)
It should change from this:
to this:
I have written a script but it isn't working and I am not getting an error message.
I have a feeling it is because I am trying to "+1" my array to offset my values. Please help!
Here is my current script:
function shift() {
try{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var as = ss.getActiveSheet();
var ar = as.getActiveRange();
var vals = ar.getValues(); // get values from the active (selected) range...... intended use is to draw a selection where the PO BOX substring is in the leftmost column
// SpreadsheetApp.getUi().alert(vals); //for checking values
var r; // variable for rows
for (r = 0; r < vals.length; r++){ // for each row, up to the last row (iterate over all rows from top to bottom)
if(vals[r][0].indexOf("PO") != -1){ // if first column in each row contains "PO"
SpreadsheetApp.getUi().alert("found a PO BOX"); // make annoucement
var c; // variable for columns
var cols = []; // array for column data (for debugging)
for (c = 0; c < vals[r].length; c++){ // for each columns in row (iterating over each cell in row from left to right)
cols[c] = vals[r][c]; // add the current cell value to an array
vals[r][c+1] = vals[r][c]; // take the value from the current cell and assign it to the next cell (+1 to the column)
}
SpreadsheetApp.getUi().alert(cols); // show me the data that cas changed
}
}
ar.setValues(vals); // set new values to active range
}
catch(err){
SpreadsheetApp.getUi().alert(err);
}
}
Expectations:
get the data range (my intended testing range is B:1 to D:12)
iterate through each row, and on each row, iterate through each
cell(column)
If the very first cell in the current row(vals[r][0]) contains the
substring "PO" , then I want to change the values of that row such
that they all shift over by one column, and leave the very first
cell as a blank string
I change the values by replacing the current values with the same
values BUT +1 to the columns row(vals[r][c]) = row(vals[r][c+1])
Realit(EDIT)y:
Exceeded memory limit error... possible infinite loop happening... i THINK it might be because I am adding a column that does not exist in the data range, but how would I get around this problem?
SOLVED!!!!
After much trial and error, I cane up with an answer (posted int he answers)
feels great to solve my own problem for the first time ever!
my problem was exactly what i expected. I was trying to assign values outside of the range.
The way that I solved this was to assign all of my values to an array(I also shifted them over in the process), and then loop through the range(the range is just a two dimensional array), assigning all of the shifted values to the range columns.
function shift() {
try{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var as = ss.getActiveSheet();
var ar = as.getActiveRange();
var vals = ar.getValues();
var r; //variable for rows
for (r = 0; r < vals.length; r++){ // for each row, up to the last row (iterate over all rows from top to bottom)
if((vals[r][0].indexOf("PO") != -1)||(vals[r][0].indexOf("P0") != -1)){ // if first column in each row contains "PO"
var c; // variable for columns
var cols = []; // array to store all data temporarily (will be uses to set new values later)
for (c = 0; c < vals[r].length; c++){ // then iterate over each column(cell) in the row
if(c == 0){ // if it is the first row,
cols[c+1] = vals[r][c]; // assign second index of the array with the PO value (to simulate a shift)
cols[c] = ""; // assign the first index of the array a blank string
}
else{ // if it is not the first row
cols[c+1] = vals[r][c]; // assign each additional column value to the next index (+1) of the array
}
}
for (c = 0; c < vals[r].length; c++){ // once the array is finished, loop through the columns again foreach row
vals[r][c] = cols[c]; // this time, assigning the new values to the corresponding array indices
}
}
}
ar.setValues(vals); // now, set the values that you reassinged to the array
}
catch(err){
SpreadsheetApp.getUi().alert(err);
}
}

2D array reading issue?

I want to create a sort of "stack" and every time I delete an item, the sheet removes the blank cells. I can't use a filter function for this, obviously.
I am having trouble reading the array that is created for this purpose.
My very pseudo-code : I create an empty array, get all the values (including the empty ones), populate my array with all the values except the empty ones, and finally clear the stack and set the values with my array.
Here is my code :
function updateStack() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("main");
var zone = sheet.getRange(1, 1, 1, 10);
//seems that .getValues() returns a 2d array
var values = zone.getValues();
var j = 0;
var data = new Array();
for (var i = 0 ; i < 10 ; i++) {
//the problem seems to be here : I can't access the 2d array. After reading the debugging console about 1000 thousand times
// I discovered the 2 pairs of []
//I've found multiple ways to detect empty cells. Not sure if this is the right one. I've tried the .length = 0 trick, but something
// was wrong, maybe because of the "2dimensionality"
if (values[i] != "") {
data[j] = values[i];
j = j++;
} else {
// do nothing if the cell contains nothing
}
//not sure if I have to use return ! Don't know where to put it exactly too...
return data;
zone.clear();
//length of range must be the same as the array's length
zone = sheet.getRange(1, 1, 1, data.length);
zone.setValues(data);
}
}
There are many comments in my code, I hope you will understand.
A link to my test sheet : http://bit.ly/1JiWutn
Thanks for any help !
Currently, you have a section of code like this:
if (values[i] != "") {
data[j] = values[i];
j = j++;
} else {
You are testing for an empty string:
values[i] != ""
But values[i] is an inner array. Your code is getting only one row, and 10 columns.
var zone = sheet.getRange(1, 1, 1, 10);
So, the array looks like this:
[ [cell one,cell two,cell three,etc,cell ten ] ]
values[i] returns an inner array, not a value.
To get the cell value use:
if (values[0][i] != "") {
You need two indexes, the first index will always be zero. There is only one inner array with all the cell values in it.
Next, use push to add a value to the data array:
data.push(values[0][i]);
Another issue is where you have the return statement. A return statement kills the current function. Anything after the return statement inside of that function will not run. So, you can't have a return statement where you have it, and get the code to write values to the spreadsheet. You can do both. You can both write values to the sheet, and return something, but put the return at the end. The return, returns something to whatever function called this function.
To set values, the values MUST be in a two dimensional array. Your data array is not a 2D array. You must add the data array to yet another array.
var my2Darray = [];
my2Darray.push(data);
zone = sheet.getRange(1, 1, 1, data.length);
zone.setValues(my2Darray);
If you are only testing for blank cells across a whole row then the test you have is almost usable. If you concatenate all the values in that array then the resultant can be compared to "".
// join all the values with nothing between them
// compare the result to empty string
if(values[i].join("") !== "") {
// if at least one cell contained something
data.push(values[i]); // Stackius Popularious
}

Reducing Google Apps Script execution time with using an array?

I wrote a script to periodically copy data from one column depending on if each cell was determined to have current data (Designated as ALIVE in another column), and place that data in another column in a different sheet. The script doesn't exceed the execution time, however I was wondering if there was a way to make it faster by utilizing Arrays.
I appreciate the help, I'm new to Google Apps Script programming but plugging along. Many thanks in advance for the advice.
function copyFunctionDATA() {
var defSheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("(DATA)")
var defSheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("(DATAdead)")
var numLastRow = 60
for (var x=11; x<=numLastRow; x++) {
var srcRange = defSheet1.getRange(x,1);
var srcRange2 = defSheet1.getRange(x,1);
var value = srcRange.getValue();
var value2 = srcRange2.getValue();
if (value2.indexOf("ALIVE") !== -1) {
defSheet2.getRange(x,1).setValue(value);
}
}}
Transposing in 2D array is very simple. The main difference is the way data is indexed : ranges count from 1 and arrays count from 0.
So to transpose your code you should get 2 arrays (one for each sheet) and iterate the corresponding cells, change the value depending on your condition and write back the array to the spreadsheet to update it.
Here is a rough transpose of your code with a couple of comments to explain : (some variables ought to be renamed for clarity)
function copyFunctionDATA() {
var defSheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("(DATA)").getDataRange().getValues();// read the whole sheet in a 2D array
var defSheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("(DATAdead)").getDataRange().getValues();// read the whole sheet in a 2D array
var numLastRow = 59 ; // I suppose you intentionally limit to the 60 first rows ?
for (var x=10; x<=numLastRow; x++) { // starting from row 11 >> becomes 10
var value = defSheet1[x][0];
var value2 = defSheet1[x][0]; // you made a mistake in your code : you define 2 identical ranges !! change it to your need : 0 is column A, 1 is B etc...
if (value2.indexOf("ALIVE") !== -1) {
defSheet2[x][0] = defSheet1[x][0];
}
}
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("(DATAdead)").getRange(1,1,defSheet2.length,defSheet2[0].length).setValues(defSheet2);// write back defSheet2 array to sheet (DATAdead)
}
EDIT : if you want to overwrite only the first column in defSheet2 change simply the range definition for this sheet, for example like this :
var defSheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("(DATAdead)").getRange('A1:A').getValues();// read the whole sheet in a 2D array