I have tried using/altering other forum's answers and can't seem to get the code right. I am wanting to repeat entire lines 'x' number of times (x being in column U). This will be a document that I use over and over again with changing data in the lines, and just need a macro to dictate how many times the line repeats. I am a total coding novice-- any advise helps!
Use the following code that shall copy range from A:U and copy is below:
function repeatrow() {
var ss = SpreadsheetApp.getActive();
var repeattime = ss.getRange('U3').getValue();
ss.getRange('A4:U').clearContent();
var value = ss.getRange('A3:U3').getValues();
for (i = 0; i <= repeattime - 1; i++) {
ss.getRange("A" + (i + 4) + ":U" + (i + 4)).setValues(value);
};
};
Related
Sorry in advanced for bad English. I have 15+ rows and 15+ columns. I need to merge cells in a spreadsheet but data will be unclear after merging. Is there a formula/function I can use to clarify my merge? Thank you in advance.
Please view example spreadsheet.
This is not possible using only formula. Formulas can't do anything to formatting like merging cells and applying colors to text. But here's a script you can use to begin with. You may modify it to apply font color.
Try:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("Sheet1");
var destSheet = ss.getSheetByName("Sheet2");
var sourceData = sourceSheet.getRange(2, 1, sourceSheet.getLastRow() - 1, sourceSheet.getLastColumn()).getValues();
//Add name to each column, add here if you have more columns
sourceData.forEach(function (x) {
x[2] = x[1] + ":\n" + x[2]
x[3] = x[1] + ":\n" + x[3]
});
var array = sourceData,
hash = {},
i, j,
result,
item,
key;
for (i = 0; i < array.length; i++) {
item = array[i];
key = item[0].toString();
if (!hash[key]) {
hash[key] = item.slice();
continue;
}
for (j = 1; j < item.length; j++) hash[key][j] = hash[key][j] + "\n" + item[j];
}
result = Object.values(hash);
destSheet.getRange(2, 1, result.length, result[0].length).setValues(result);
}
Result:
Reference:
How to merge an array of arrays with duplicate at index 0 into one array javascript
Hope this helps!
You can try with this formula, adapt the column range in the MAP function if necessary:
={UNIQUE('raw data'!A2:A),
SCAN(,UNIQUE('raw data'!A2:A),
LAMBDA(x,city, BYCOL(IFNA(FILTER ({'raw data'!B2:B,
MAP('raw data'!C2:G,LAMBDA(a,IF(a="","",INDEX('raw data'!B:B,ROW(a))&":"&CHAR(10)&a)))},'raw data'!A2:A=city,'raw data'!A2:A<>"")),LAMBDA(col,JOIN(CHAR(10)&CHAR(10),col)))))}
Maybe I'm missing a keyword in my searches for a solution, but I didn't find what I'm looking for.
In Google Sheets I want to take a set of numbers and reorder it randomly. For example, start with the set [1,2,3,4] and get back [4,2,1,3].
Any ideas which function or a combination of functions may achieve this goal?
The entire process that I want to achieve is something like this:
I have a set of 4 fields. Their sum is fixed. I want to assign them randomized values.
So, I was thinking to iterate through this process:
Create a random integer between 0 and the max possible value (in the first iteration it's the fixed sum)
The new max value is the last max value minus the new random number.
Check if the new max is zero.
If not:
Return to the 1st step and repeat - This goes on until there are four values
If needed the 4th value shall be increased so the total will match the fixed sum.
Else, continue.
Randomize the order of the 4 values.
Assign the values to the 4 fields.
try:
=INDEX(SORT({{1; 2; 3; 4}, RANDARRAY(4, 1)}, 2, ),, 1)
or:
=INDEX(SORT({ROW(1:4), RANDARRAY(4, 1)}, 2, ),, 1)
Here are a couple of app script examples as well
function DiceRolls(nNumRolls) {
var anRolls = [];
nNumRolls = DefaultTo(nNumRolls, 1000)
for (var i = 1;i <= nNumRolls; i++) {
anRolls.push(parseInt((Math.random() * 6))+1);
}
return anRolls;
}
function CoinFlips(nNumFlips) {
var anFlips = [];
nNumFlips = DefaultTo(nNumFlips, 1000)
for (var i = 1;i <= nNumFlips; i++) {
anFlips.push(getRndInteger(1,2));
}
return anFlips;
}
function getRndInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1) ) + min;
}
I am trying to use a google sheet to rank a list of elements. This list is continually updated, so it can be troublesome to update the list if i already have hundreds of elements ranked and need to rank 10 new ones. Rather than having to re-rank some of the previously ranked elements every time (whether manually or using formulas), i thought it easier to write a macro that would re-rank for me.
1 - element A
2 - element B
3 - element C
new element: element D
For instance if i wanted element D to be ranked 2nd, i would need to change element B to 3 and element C to 4. This is tedious when doing hundreds of elements.
Here is my code so far but I get stuck with the getRange lines. Rankings are in column A.
function RankElements() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var r = s.getActiveCell();
var v1 = r.getValue();
var v2 = v1 + 1
var v3 = v2 + 1
var lastRow = s.getLastRow();
s.getRange(1,v2).setValue(v2);
s.getRange(1,v3).autoFill(s.getRange(1,v3+":"+1,lastRow), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
s.getRange(1,v3+":"+1,lastRow).copyTo(s.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
s.getFilter().sort(1, true);
};
You can do the following:
Iterate through all values in column A.
For each value, check if (1) ranking is equal or below the new one, and (2) it's not the element that is being added.
If both these conditions are met, add 1 to the current ranking.
It could be something like this:
function RankElements() {
const sheet = SpreadsheetApp.getActiveSheet();
const cell = sheet.getActiveCell();
const row = cell.getRow();
const newRanking = sheet.getActiveCell().getValue();
const firstRow = 2;
const columnA = sheet.getRange(firstRow, 1, sheet.getLastRow() - 1).getValues()
.map(row => row[0]); // Retrieve column A values
for (let i = 0; i < columnA.length; i++) { // Iterate through column A values
if (columnA[i] >= newRanking && (i + firstRow) != row) {
sheet.getRange(firstRow + i, 1).setValue(columnA[i] + 1); // Add 1 to ranking
}
}
sheet.getFilter().sort(1, true);
};
I am trying to query 2 long columns for agents' name, the issue is the names are repeated on 2 tables, one for the total sum of productivity and the other is for total sum of utilization.
The thing is when I query the columns it returns back the numbers for Productivity and Utilization all together.
How can I make the query to search only for Productivity alone and for Utilization alone?
Link is here: https://docs.google.com/spreadsheets/d/12Sydw6ejFobySHUj5JoYkAPbhr0mKoInCWxtHY1W4lk/edit#gid=0
Apps Script would be a better solution in this case. The code below works as follows:
Gets the names from Column D and Column A.
For each name of Column D, it will compare it with each name of Column A (that's the 2 for loops)
If the names coincide (first if), it will check the background color (second if) of the Column A name to accumulate Total Prod and Total Util.
Once it reaches the end of the Column A, writes the values in Total Prod and Total Util (Columns E and F) for each name in D.
function onOpen() { //Will run every time you open the sheet
//Gets the active Spreadsheet and sheet
let sprsheet = SpreadsheetApp.getActiveSpreadsheet();
let sheet = sprsheet.getActiveSheet();
var lastRow = sheet.getLastRow();
var getNames = sheet.getRange(3, 1, lastRow).getValues(); //Names from row 2, col 1, until the last row
var totalNames = sheet.getRange("D4:D5").getValues(); //Change the range for more names
let prodColor = '#f2f4f7'; //hexadecimal codes of the background colors of names in A
let utilColor = '#cfe2f3'; //
for (var i = 0; i < totalNames.length; i++) {
var totalProd = 0, totalUtil = 0; //Starts at 0 for each name in D
for (var j = 0; j < getNames.length; j++) {
if (totalNames[i][0] == getNames[j][0]) {
if (sheet.getRange(j + 3, 1).getBackgroundObject().asRgbColor().asHexString() == prodColor) { //if colors coincide
totalProd += sheet.getRange(j + 3, 2).getValue();
} else if (sheet.getRange(j + 3, 1).getBackgroundObject().asRgbColor().asHexString() == utilColor) {
totalUtil += sheet.getRange(j + 3, 2).getValue();
}
}
}
sheet.getRange(i+4, 5, 1 ,2).setValues([[totalProd, totalUtil]]);
}
}
Note: You will have to run the code manually and accept permissions the first time you run it. After that it will run automatically each time you open the Sheet. It might take a few seconds for the code to run and to reflect changes on the Sheet.
To better understand loops and 2D arrays, I recommend you to take a look at this.
References:
Range Class
Get Values
Get BackgroundObject
Set Values
You can learn more about Apps Script and Sheets by following the Quickstart.
I have an Input column with a sequence of two different letters. As result I want to get something like on the picture. This formulas I will use with ARRAYFORMULA to get unlimited count of rows. To get BLOCK № I was trying to use =COUNTIFS($B$2:B2,"N") but it works only if I copy the formula manually down the column, but if I do:
=ARRAYFORMULA(COUNTIFS(($B$2):(B2:B),"N"))
It doesn't work.
How can I replicate the behavior of this function without needed to manually copy it?
I'd recommend writing a script to fill the Block Nos.
I'll assume the topmost letter begins at cell input!A4 and you want the Block Nos from cell input!C5 and below. Go to the menu bar of the spreadsheet and select Script Editor. Then write the following scripts:
//the main function
function writeBlocks() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('input');
var numRows = sheet.getLastRow();
var startRow = 4;
var inputCol = 1;
var outputCol = 3;
var block = 0;
//clear old Block Nos
sheet.getRange(startRow, outputCol, numRows - 3, 1)
.clearContent();
//recalculate LastRow in case there are fewer new inputs than old outputs
numRows = sheet.getLastRow();
//get input data
var input = sheet.getRange(startRow, inputCol, numRows - 3, 1)
.getValues;
//write output data
for (var i = 0; i < input.length; i++) {
block += input[i] == "N" ? 1 : 0;
sheet.getRange(startRow + i, outputCol)
.setValue(block);
}
}
//create new menu
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Calculate blocks", functionName: "writeBlocks"});
ss.addMenu("Custom functions", menuEntries);
}
Save it all, refresh the spreadsheet, and there should be a new option on the menu bar. When you select that option, it will clear the old Block Nos and generate new ones based on the current inputs. Hope this helps.