I am very new to programming and I am trying to create a short macro on google sheets. I want to copy and paste a list of cells a certain number of times based on variables see here. On the first column you have a list of locations and the second column the number of times they should be pasted into a 3rd column (column F). For example i would like to paste A4 fives times into column F4. Then A5 twice into F8 (F4 + 5 rows) and so one until the end of my list.
I came up with the below code but it currently copies each locations of my list 5 times on the same rows (F4-F8) then repeat the same process on the following 5 rows, and so on. I think the issue is with the order of the loops but i can't figure it out really.
Another problem i have is that It only copies each location 5 times (B1), but i am not sure how to make my variable numShift an array for (B4-B16) so that each locations is copied the correct number of times
Any help would be really appreciated !
function myFunction() {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet()
var activeSheet = ss.getActiveSheet()
var numShift = activeSheet.getRange(4,2).getValue()
for (var k=0;k<65;k=k+5){
for (var indexNumLocation=0;indexNumLocation<15;indexNumLocation++){
for (var indexNumShift=0;indexNumShift<numShift;indexNumShift++)
{var locationRange = activeSheet.getRange(4+indexNumLocation,1).getValue();
activeSheet.getRange(4+k+indexNumShift,6).setValue(locationRange);
}
}
}
}
Try this
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lastRow = sheet.getLastRow();
var data = [];
var i, j;
// get times count for each row from B4 to last row
var times = sheet.getRange(4, 2, lastRow - 4, 1).getValues();
// get the data that needs to be copied for each row from A4 to last row
var values = sheet.getRange(4, 1, lastRow - 4, 1).getValues();
// loop over each row
for (i = 4; i <= lastRow; i++) {
// run loop number of times for that row
for (j = 1; j <= times[i]; j++) {
// push the value that needs to be copied in a temporary array
data.push([values[i][0]]);
}
}
// finally put that array data in sheet starting from F4
sheet.getRange(4, 6, data.length, 1).setValues(data);
}
Related
I have a table with data in columns A:Ak. Some of the data contains formulas and when a row of data is complete (i.e. the status in column W is "Y") I would like to copy that row in place and only past the values.
This is what I have tried:
function Optimize() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
// This searches all cells in columns W copies and pastes values in row if cell has value 'Y'
if (row[22] == 'Y') {
sheet.getDataRange(sheet.getCurrentCell().getRow() - 0, 1, 1, sheet.getMaxColumns()).activate();
sheet.getActiveRange().copyTo(sheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
rowsCopiedpasted++;
}
}
}
When I am in the sheet and click on the cell in column A of a row with a "Y" value this works, but I need it to go through the whole sheet and copy/paste values of all rows with "Y" in column W.
Try this:
function Optimize() {
const sh = SpreadsheetApp.getActiveSheet();
const rg = sh.getDataRange();
const vs = rg.getValues();
const lc = sh.getLastColumn();
let o = vs.forEach((r,i) => {
if(r[22] == "Y") {
sh.getRange(i + 1, lc + 1,1,lc).setValues([r])
}
});
}
I am trying to sort values of column A depending on the values at column B ordered by matching keys at column E expected results are in column C
I can achieve this through formula described here
=SORT(A2:A;ARRAYFORMULA(MATCH(B2:B;E2:E;0));1)
I am seeking a google script answer to enhance its automation by using it through onEdit trigger. I can sort column A according to column B alphabetically through this pseudocode snippet. I need help on attaching this the numeric order of sort key
var sortRange = sheet.getRange(2,1,lastRow,lastCol)
sortRange.sort({column: 2, ascending: false});
Thanks in advance
====== Update ======
Found a Solution Thanks to ziganotschka
// Retrieve Keys&Range
var sortKeys = ss.getRange(2, 5, 3, 1).getValues().flat();
var sortRange = ss.getRange(2,1,lastRow,2).getValues();
// Set an index to each row according to its relation to the search keys
for (var ii=0; ii < sortRange.length; ii++){
var index = sortKeys.indexOf(sortRange[ii][1]);
sortRange[ii].push(index);
}
// Sort the array ascending by index
activeCell.setValue(sortRange[0][2]);
sortRange.sort(function(a,b) {
var varA = a[2];
var varB = b[2];
return varA == varB ? 0 : varA > varB ? -1 : 1;
});
// Reduce the array to the sorted values of Column A
var sortedColumn = sortRange.map(function(i){return [i[0]];});
//set values into column C
ss.getRange(2, 6, sortedColumn.length, 1).setValues(sortedColumn);
If you want to sort by script instead of formula, you have to do it differently
sortRange.sort will sort you current spreadsheet contents rather than outputting the sorted version in a new column
Instead you need to retrieve the values as an array and perform a Javascript array sorting function on it: Array.prototype.sort()
Also, if you want to sort by searchkeys in column E, rather than alphabetically / numerically, you need to append to the retrieved array an index column based on a row's relation tot he search key
The index can be retrieved with Array.prototype.indexOf()
After you sort the three column array (column A, column B and the new index column), reduce the array to the sorted values column and set it into column C with setValues(values)
Sample:
function myFunction() {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var lastRow = sheet.getLastRow();
var lastCol = 2;
var sortRange = sheet.getRange(2,1,lastRow-1,lastCol).getValues();
//retrieve the keys in column E
var keys = sheet.getRange(2, 5, lastRow, 1).getValues().flat();
for (var i =0; i < sortRange.length; i++){
//set an index to each row according to its relation to the search keys
var index = keys.indexOf(sortRange[i][1]);
sortRange[i].push(index);
}
//sort the array ascending by index
sortRange.sort(function(a,b) {
return a[2] - b[2]
});
//reduce the array to the sorted values of Column A
var sortedColumn = sortRange.map(function (i){return [i[0]];});
//set values into column C
sheet.getRange(2, 3, sortedColumn.length, 1).setValues(sortedColumn);
}
picture of add rows example
As the picture shows, there are 11 rows of numbers in Column A,
I want to add rows to it and make it shows as the numbers in column D
You see for every 3 rows of number in A, I want to add a new row to its up and bottom, the new row in the top with value "0", and the bottom row with the sum value of these three rows of numbers
for example
the first three rows are 1,2,3, and their sum is "1+2+3=6"
the second three rows are 4,5,6, and the sum is "4+5+6=15"
the third three rows are 7,8,9, and the sum is "7+8+9=24" as picture shows
and you see the last part of the column are "10 and 12", which are two rows
(less than three rows), but in this case, it still need to add two new rows, one row in top with"0" and one row in bottom with its sum "10+12=22"
Right now, I wrote two for loop function to insert the rows
function insertRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("sheet1");
var numRows = SpreadsheetApp.getActiveSpreadsheet().getSheetByName ("sheet1").getLastRow();
for (var i=1; i <= numRows+2; i+=4) {
var addrow = sheet.insertRowsBefore(i,1);
}
}
function insertRows2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("sheet1");
var numRows = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet1").getLastRow();
for (var j=4; j <= numRows+2; j+=5) {
var rowadd= sheet.insertRowsAfter(j,1)
}
}
"insertRows()" is used to insert the head row, "insertRows2()" is used to insert the bottom row,
so far these two functions are working good to insert the rows in right place, but I don't know how to fill in the top rows with "0"s in the loop and how to fill the sum value of each three rows of numbers in the bottom rows.
Do you guys know how to fill in the rows with the right values?
How about this sample script? I think that there are several answers for your situation. So please think of this as one of them.
Flow :
Retrieve values from "A1:A11" of sheet1.
Using the retrieved values, it creates an array for the result.
At first, it separates the values, while inserts 0 to the top and the sum of the end.
As an important point, the array is created to put the spreadsheet as 2 dimensional array.
Put the result values to "D1:19" of sheet1.
Sample script :
function insertRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("sheet1");
var value = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues().filter(Number);
var result = [];
var temp = [[0]];
var sum = 0;
for (var i = 0; i < value.length; i++) {
temp.push(value[i]);
sum += value[i][0];
if ((i + 1) % 3 == 0 || i == value.length - 1) {
temp.push([sum]);
result = result.concat(temp);
temp = [[0]];
sum = 0;
}
}
sheet.getRange(1, 4, result.length, 1).setValues(result);
}
Note :
When run this sample script, the lastrow of the sheet is changed. So I used filter() to var value = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues().
If this was not what you want, please tell me. I would like to modify my answer.
Say I have Account Numbers, Sub-account Numbers and values in a google spreadsheet where there can be duplicate Account Numbers with different sub-acc numbers:
acc no / sub acc no / val
2 / 5 / 6
3 / 10 / 8
4 / 9 / 2
2 / 14 / 1
After I sort the whole sheet by the third column, values, it's gonna look like this:
acc no / sub acc no / val
3 / 10 / 8
2 / 5 / 6
4 / 9 / 2
2 / 14 / 1
So, what I want to do is to group all meters under the same accounts while having the original sort remain intact:
acc no / sub acc no / val
3 / 10 / 8
2 / 5 / 6
2 / 14 / 1
4 / 9 / 2
Seems like after sorting it by values, I need a script that loops through the account No column, for each cell it will check the remaining account numbers, and if there's a matching duplicate one, it's gonna get moved up.
This is what I could come up with so far:
function group(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
// find how many accounts we have
var Avals = sheet.getRange("A2:A").getValues();
var Alast = Avals.filter(String).length;
for (var i = 0; i < Alast-2; i++) {
if(Avals[i].toString() == Avals[i+1].toString()){
continue;
}
for (var j = i+2; j < Alast; j++){
if(Avals[i].toString() == Avals[j].toString()){
//move
break;
}
}
}
}
Thanks in advance!
This is a sample script. Untested. Assumes Sheet is already sorted by C column.
function group(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// find how many accounts we have
//get A2:C range& values
var rng = sheet.getRange(2,1,sheet.getLastRow()-1,3);
var val = rng.getValues();
var data =[];//output array
var k=0; //data array new row count
//loop through existing rows
for(i=0;i<val.length;i++){
//if A is not empty, new k row data array = original row.
if (val[i][0]) { //value check
data[k] = val[i];
k++; //increment k to next row
//Loop through rows after current row to find next similar A value,if any
for(j=i+1;j<val.length;j++) {
if (val[i][0] == val[j][0]) { //if one of the folllowing row's A value is == current A value
data[k] =val[j].slice(0); //new k data array = j row
k++; //increment k
val[j][0] =''; //set the duplicate j row's A value to null to skip during value check
}
}
}
}
//Logger.log(data);
sheet.getRange(2,1,data.length,data[0].length).setValues(data);
}
I'm working on a Texas Holdem game and i need to generate all possible k subsets from an Array of cards (represented as numbers in this example). This is how it looks so far:
public function getKSubsetsFromArray(arr:Array, k:int):Array {
var data:Array = new Array();
var result:Array = new Array();
combinations(arr, data, 0, arr.length - 1, 0, k, result, 0);
return result;
}
public function combinations(arr:Array, data:Array, start:int, end:int, index:int, r:int, resultArray:Array, resultIndex:int):int {
if (index == r) {
trace(resultIndex, data);
resultArray[resultIndex] = data;
return ++resultIndex;
}
for (var i:int = start; i<=end && end-i+1 >= r-index; i++) {
data[index] = arr[i];
resultIndex = combinations(arr, data, i + 1, end, index + 1, r, resultArray, resultIndex);
}
return resultIndex;
}
I am new to Actionscript, my idea is to have a function that takes an array of number and a parameter k, and returns an Array of arrays each of size k. However once i test the functions I get an array containing only the last combination nCk times. For example:
var testArray:Array = new Array(1, 2, 3, 4, 5);
trace(getKSubsetsFromArray(testArray, 3));
Returns:
0 1,2,3
1 1,2,4
2 1,2,5
3 1,3,4
4 1,3,5
5 1,4,5
6 2,3,4
7 2,3,5
8 2,4,5
9 3,4,5
The function output is
3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5
Of course it should print an array containing all the combinations listed before but it only prints the last one the right amount of times.
Thank your for your help.
The reason for the error is that when you are making array of arrays you are actually using the reference of the same array (data) so when the last combination is executed the contains of data array become 3,4,5 and each of index of resultArray points to data array so it prints out same values.
Solution :-
if (index == r) {
trace(resultIndex, data);
var result = new Array();
copy(result,data)
resultArray[resultIndex] = result;
return ++resultIndex;
}
Note :-
The above is pseudo code as i am not familiar with actionscript but you can implement copy function that copies values of data into result in actionscript syntax.