how to get maximum index of array in appscript - google-apps-script

I tried to get the values in a row into an array. For this I used the appscript in googlesheet. After checking the length of this rowtemp array, the answer is 1.
But I want to find the number of children inside. And if the element in "temp" is the same as the one in "rowtemp" then you need to find its column number
I used following code.
function rangeExa(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet4");
var temp = ss.getRange("A11:B22").getValues();
Logger.log(temp);
Logger.log(temp.length);
Logger.log(temp[3][0]);
var rowTemp = ss.getRange("D25:O25").getValues();
Logger.log(rowTemp);
Logger.log(rowTemp.length);
Logger.log(rowTemp[0][2]);
Logger.log(rowTemp);
for(i=0; i<=rowTemp.length; i++){
if(temp[3][0] == rowTemp[0][i]){
Logger.log("yessss");
}return;
}
}

As I explained in detail in the comment section, your goal is not clear.
However, there is a clear issue in the code an that relates to the length of rowTemp.
rowTemp is an array of a single array because it concers a single row. In other words, it has the format of [["High","Not High",..]]. Therefore, rowTemp.length will give you 1 since there is only one row in this array. If you want to iterate over the columns, you need to use rowTemp[0].length:
for(i=0; i<rowTemp[0].length; i++){
if(temp[3][0] == rowTemp[0][i]){
Logger.log("yessss");
Logger.log(i+4); // column number if there is a match
}
}
The above for loop will check if 36 appears in D25:O25 and it will output yessss if it does in the Logs page.
Also use i<rowTemp[0].length instead of i<=rowTemp[0].length because the last index of your array is rowTemp[0].length-1 otherwise you will get undefined.
Related:
What does the range method getValues() return and setValues() accept?

Related

Data into rows and colums

I'm relatively new to this, I've written a function in Google Apps Script, getting data from an API.
The problem is that it's inserted into one single cell, instead of multiple rows and columns.
Can anybody help?
Tried googling examples
What I do
function spotpriser() {
var priser = 'api.energidataservice.dk/dataset/Elspotprices' + '?start=2022-07-01&end=2022-07-02' + '&sort=HourDK';
var response = UrlFetchApp.fetch(priser);
Logger.log(response);
var fact = response.getContentText();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1,1).setValue([fact]);
}
if you do getRange(1,1).setValue() it is normal that all the data get inserted into one cell only: the one define by the range (aka A1).
Instead what you probably want to do is to get a larger range, corresponding the dimensions of your retrieved data.
For example, let's say you retrieved 3 lines of data, and one line of data is supposed to be displayed on 2 columns.
You first need to create an array of size 5 (nb of rows) where each element will also be an array, of size 2 (nb of cols for each element).
let myArray = [
[elt1_col1_value, elt1_col2_value],
[elt2_col1_value, elt2_col2_value],
[elt3_col1_value, elt3_col2_value]
]
Then you can insert this array into the right number of cells, i.e defining the right range
sheet.getRange(1,1,myArray.length,myArray[0].length).setValues(myArray); // start at row 1, col 1, insert the right number of rows and cols based on the array
Note that I use setValues (with the s) to indicate that it writes in several cells.
Also make sure there is at least one element in myArray otherwise myArray[0].length will throw an error.
Documentation for getRange.

How do I get values of a column in an array and search for a value in it? (Google Sheets' Apps Script)

I have this sheet in my Google sheets spreadsheet which looks like this - (this is a simpler representation of my actual data)
Now let's say I want to find the row number of where animal = dog - wrt above data I should get 4 in return - as in the column 1, the value "dog" is in the 4th row. I built this code in Apps Script but it keeps returning -1 and I don't understand why...
var values = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
Logger.log(values);
//above prints [[animal, owner], [cat, Max], [doggo, Sam], [dog, Jack], [cow, Mary], [rabbit, Jimmy]]
var index = values[0].indexOf("dog");
var responsePrint = index;
Logger.log(responsePrint); // -1 is printed
What should I do if I want to get the 1st column of my sheet in an array and search for a particular value in it? I'm trying to avoid using a loop to scan each and every element, as my data might get large - so if an inbuilt function can do this, it'd be great for me... Any idea is appreciated! Thanks :)
P.S. I'd like to say this might sound like a question which has been asked before, but trust me I've searched a lot, and I can't seem to find a suitable solution for me...
values is a 2D array, or an array of arrays. The first index of values is the row and the second index is the column so values[1][0] would be the second row first column.
So in your case you could do this.
let index = values.findIndex( row => row[0] === dog );
To get the row you have to add 1 to the index because index are zero based.
What findIndex does is it takes each element of values which is a "row" and then looks at the first value in the row array and compares to "dog"
Reference
Array.findIndex()
Arrow function
If you want to use indexOf you need to isolate the first column of your data and then use the indexOf method:
function myFunction(){
var values = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
var index = values.map(r=>r[0]).indexOf("dog") + 1;
console.log(index); //outputs 4
}

Issues using setValues function

I keep getting an error message when using the setValues() function to export an array to Google sheets. I have tried many different methods for creating my 2D array, but I still keep getting the same errors. Sometimes my code will run (the array will export to the spreadsheet) but I will still get an error.
I originally used the setValue() function in a for loop but the code would time out because it ran too long. So I tried dumping all my data into a 2D Array and feeding that to the spreadsheet all at once.
Tried creating the Array as an empty 2D array
var outputArray = [[]]
and using .push to populate the data into it
Tried creating the empty Array using the function:
function create2DArray(rows) {
var arr = [];
for (var i=0;i<rows;i++) {
arr[i] = [];
}
return arr;
}
and adding the data in by rows (inside of a for loop that iterates by rowNumber)
outputArray[rowNumber] = [data1, data2, data3,...]
Used the same function above for creating empty array and created intermediate array and then put that into output array
outputArrayIntermediate[0] = data1;
outputArrayIntermediate[1] = data2;
outputArrayIntermediate[2] = data3;
outputArrayIntermediate[3] = data4;...
outputArray[rowNumber] = outputArrayIntermediate;
Here is where the error keeps happening
var setRows = outputArray.length;
var setColumns = outputArray[0].length
revenueSheet.getRange(2,1,setRows,setColumns).setValues(outputArray);
When I include the setColumns variable I get the error:
"The number of columns in the data does not match the number of columns in the range. The data has 0 but the range has 11."
This will still populate the data to the spreadsheet.
When I do not include the setColumns variable I get the error:
"The number of columns in the data does not match the number of columns in the range. The data has 11 but the range has 1."
Is there ever an instance where one row has more columns than another row? For instance if 'row' 1 in your data as 5 columns (outputArray.length = 5) and row 2 has 6, then the data needs a range with 6 columns.
If this is the case, here are some solutions in order of simplicity:
1. If there is no important data to the right of where you are inserting you data you can use revenueSheet.getMaxColumns() in your .getRange().setValues().
2. Iterate through the data set to find the row with the longest length and set that as the number of columns. To do this see this answer for a few options.
You only need [] not [[]], because you are pushing arrays into outputArray, and push makes sure it will always expand when needed.
Try this:
outputArray = [];
outputArray.push([data1, data2, data3]);
outputArray.push([data4, data5, data6]);
revenueSheet.getRange(2,1,outputArray.length,outputArray[0].length).setValues(outputArray);
Perhaps this will help you:
function createSSData(numrows,numcols) {
var numrows=numrows || 20;
var numcols=numcols || 20;
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var values=[];
for(var i=0;i<numrows;i++) {
values[i]=[];
for(var j=0;j<numcols;j++) {
values[i].push(Utilities.formatString('row: %s,col: %s',i+1, j+1));
}
}
sh.getRange(1,1,values.length,values[0].length).setValues(values);
}

Cannot read property from undefined

I have the following code, which works fine and does what it's supposed to do.
However my table has 2 rows at the top which doesn't interest me (they wouldn't match the if clause anyway so it doesn't affect me, just trying to figure this out) so I was trying to tailor my range to simply exclude them.
All I did was change the A1 to A3 inside the getRange and it's throwing the Cannot read property "1" from undefined (referring to the hardcoded 1 in the if statement).
The reason I don't understand why it's undefined is because changing the range like this shouldn't affect it at all, since I'm reducing my range from A1:B6 (6 rows in my sheet with the first 2 being either empty or not needed) to A3:B6, but the first value in the set (A3) should still end up at [0][0] inside 'data'.. unless getValues() messes something up that I don't know about..
var lastRow = sheet.getLastRow();
var myRange = sheet.getRange("A1:B" + lastRow);
var options = new Array();
var data = myRange.getValues();
for(var i = 0; i < lastRow; i++) {
if(data[i][1] == region)
{
options.push(data[i][0]);
}
}
Thanks!
Your bug stems from your for loop; it expects to iterate over 6 rows (i starts at 0 and increments by 1 up to 5), when what you really want is to iterate over 4 rows matching the range A3:B6. So the array only has 4 elements but your for loop tries to reference a 5th element that does not exist.
Simplest solution is to use the Array object's built in array methods (I'm using forEach in this case) to iterate over the items specifically in the range you defined as follows:
var range = sheet.getRange("A3:B"), // you automatically reference the last row with A3:B, no need for A3:B6
options = [],
region = '[some-region-value]';
range.getValues().forEach(function(row){
row[1] == region && options.push(row[0]); // exploit short-circuit mechanism in logical AND operator (in this case the operand on the right, the push, only gets executed if the operand on the left is true)
});
Array indices start with zero. The index of the last element is length of an array (total number of elements) - 1. Modify your 'for' loop like this and it will work
for(var i = 0; i < data.length; i++)
As the previous poster pointed out, you iterate from 0 to what the function getLastRow() returns. Remember, it returns the last row with data in a sheet. It has nothing to do with your array.

Finding column number of a cell with specific value

I currently have a code that can get the row number of a cell that contains a specific string. Here's an example of the code:
var ss = SpreadsheetApp.getActiveSheet();
var values = ss.getRange("B:B").getValues();
var i=j=firstrow=lastrow=0;
for(i=0;i<values.length;i++)
for(j=0;j<values[i].length;j++) {
if(values[i][j]==5100) firstrow=i+1;
else if(values[i][j]=='EOL') lastrow=i-2;
}
I was wondering if it's possible to do something like above, but for columns, that way my script will not fall apart if an user accidentally move a column.
So, what are doing is using .getRange("B:B") to define that you want all rows in column B. Then using getValues() to return all of those rows as a multidimensional array(obviously this will only have one column - so you probably don't need that other for loop).
So instead you can just use .getRange(row, column) (where row and column are integers greater than 1), this way you can go through the spreadsheet one item at a time using getValue(). So you could initially look through the first row to find the column index you are after, and then look down the rows to find the data you require.
Something like this might work for you:
var ss = SpreadsheetApp.getActiveSheet();
var valueColumn;
for(i=1;i<ss.getLastColumn();i++) {
if (ss.getRange(1,i).getValue() == "ColumnName") {
valueColumn = i;
break;
}
}
//At this point I assume that we have a value in valueColumn, if not this won't work.
var values = ss.getRange(2, valueColumn, ss.getLastRow()).getValues();
var i=firstrow=lastrow=0;
for(i=0;i<values.length;i++) {
if(values[i][0]==5100) firstrow=i+1;
else if(values[i][0]=='EOL') lastrow=i-2;
}
One thing to keep in mind is that arrays are 0 based where as getRange(row,column[,rows]) is 1 based.
My spreadsheet is only small, so speed impacts of doing one call and getting all data is minimal, but if you are actually using a large sheet you might find one method works faster than another.