Make a new array with different columns - google-apps-script

I want a report with a few selected columns from a sheet.
The selection will be as per the user input like "1,4,7,12" for including column 1,4,7 and 12 in the report.
Or the input can be "2,3" to include column 2 and 3 in the report.
//user input is saved in variable input "1,4,7,8" or "2,4" or "3,2,5"
//
var jobvals = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
var flds=input.split(",");
var tstr="";
for (i=1;i<jobvals.length;i++){
for (s=0;s<flds.length;s++){
//tstr+=jobvals[i][flds[s]]+","; //I can make a comma separated string for each row. But, I want an array for further processing
//getting stuck here - how to make an array
}
tstr+="\n";
}
I want to make a new array with the selected columns. The number of columns in the result array will vary. And, the column selection will also vary.
Appreciate some ideas how to achieve this.

I got help from
Best method to extract selected columns from 2d array in apps script
Google Script GetRange with Filter based on values in a column AND select only certain columns
Solution
function extract_some_columns{
var jobvals = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
var new_array = getCols(jobvals,'['+input+']');
//new_array has only column 1,3,5 (as specified in the variable input = "1,3,5")
}
function getCols(arr,cols) {
return arr.map(row =>
row.filter((_,i) => cols.includes(++i)))
}

You can declare an empty array and add each element one by one by using push() function on an array. Your code should look like this:
var jobvals = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
var flds=input.split(",");
var tstr=[];
for (i=1;i<jobvals.length;i++){
for (s=0;s<flds.length;s++){
tstr.push(jobvals[i][flds[s]]);
}
}

Related

Setting the row Choices in a Google Form Multi Choice Grid Item?

I have used the Setting the Column Choices in a Google Form Multi Choice Grid Item? topic to produce a Apps Script which produces a dynamic Google Form Grid Item based on an underlying Google sheet.
A trigger runs on the google sheet, so that when a new record is entered, this should be replicated as a new row in the form item.
The problem I am having is if I use an array formula to populate the setRows attribute at line 20 (namesList.setRows([studentNames])) of the code, the form item is produced but each of the names is produced as a single concatenated line (i.e. Person 1, Person2, Person3 etc).
If I hard code the person elements in the setRows element at line 21 (namesList.setRows(['Person1','Person2','Person3','Person4','Person5','Person6','Person7'])) of the code, the form item is produced, with (in this instance) 7 lines, with each record having its own line. i.e.
Person1
Person2
Person3
I don't want to use a hard coded list as the list of person names could increase on a regular basis, so need to use an array to produce the list but then use the array in the setRows element.
function updateForm(){
// call your form and connect to the drop-down item
var form = FormApp.openById("FakeFormID");
var namesList = form.getItemById("FakeFormItemID").asGridItem();
// identify the sheet where the data resides needed to populate the drop-down
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("FakeSheetName");
// grab the values in the first column of the sheet - use 2 to skip header row
var namesValues = names.getRange(2, 1, names.getMaxRows() - 1).getValues();
var studentNames = [];
// convert the array ignoring empty cells
for(var i = 0; i < namesValues.length; i++)
if(namesValues[i][0] != "")
studentNames[i] = namesValues[i][0];
// populate the drop-down with the array data
namesList.setRows([studentNames]) //creates a concatenated list
namesList.setRows(['Person1','Person2','Person3','Person4','Person5','Person6','Person7']) //creates individual lines but is hard coded
namesList.setColumns(['1','2','3','4','5']);
}
Replace
studentNames[i] = namesValues[i][0];
by
studentNames.push(namesValues[i][0]);
the above is to avoid that studenNames includes empty elements.
Also instead of getMaxRows() use getLastRow() as the last it's very likely that will make your script more efficient as usually a sheet includes empty rows at the bottom that under certain circumstances might be too many.

Google Sheets Apps Script, return random item from named range

I'm trying to create a custom function that I can give a name range as input and have it output a random item from the name range. I have multiple named ranges so it would be convenient to have one function that I could use for all of them. This is what I'm trying to replace =INDEX(named_range,RANDBETWEEN(1,COUNTA(named_range)),1)
This is what I've tried but it doesn't work:
function tfunction(n) {
var randomstuffs = SpreadsheetApp.getActiveSpreadsheet().getRangeByName(n);
var randomstuff = randomstuffs[Math.floor(Math.random()*randomstuffs.length)];
Logger.log(randomstuff);
}
Thanks in advance
You can try this edited script:
function tfunction(n) {
//randomstuffs will only get all cell data that are not empty from a named range
var randomstuffs = [].concat.apply([], SpreadsheetApp.getActiveSpreadsheet().getRangeByName(n).getValues()).filter(String);
var randomstuff = randomstuffs[Math.floor(Math.random()*randomstuffs.length)];
return randomstuff;
}
Sample Result
Created a sample named range TestRange on Column A with 21 cells of data then tried the custom function =tfunction("TestRange") which returned a random cell value.
.getRangeByName() method returns a reference to a range, not the values in the range. You need to add .getValues() to it:
var randomstuffs = SpreadsheetApp.getActiveSpreadsheet().getRangeByName(n).getValues();
Also keep in mind that .getValues() method returns a 2D array of values, indexed by row, then by column. So your var randomstuff declaration will need to be change to account for that, depending on how many rows and columns your range has.

how to get maximum index of array in appscript

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?

How to split cell with delimiter to rows and repeat cells in other columns?

How do I turn this:
into this:
I want to split column C that contains data is this format to rows and then repeat data in other columns:
((60665899;); (4328899;););
Is there a google script I could use for this transformation?
Thanks!
Let us consider the following function:
function splitRows(sourceRange, targetCell) {
var values = sourceRange.getValues(), result = [];
values.forEach(function(v) {
var m = v[2].match(/\d+/g);
if (m) {
m.forEach(function(d) {
result.push([v[0], v[1], d]);
});
}
});
targetCell.offset(0, 0, result.length, 3).setValues(result);
}
The first argument is the range A2:C4 in your case, and the second one is top-left corner of the target range for the results.
The critical part is using of the regular expression to extract and separate numbers from the last column. Then we can compose resulting array and place it back to the sheet.

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);
}