Google Sheets macro to center align all dashes in top row - google-apps-script

I'm trying to use a macro to check the top row of my sheet and automatically center align all cells that have only a dash. Right now, it looks like my code is running, but it's not doing anything:
function CenterAlignAllDashes() {
var spreadsheet = SpreadsheetApp.getActive();
var topRow = spreadsheet.getRange('A1:1');
var topRowValues = topRow.getValues();
for (let i=0; i < topRowValues.length; i++) {
if (topRowValues[i] == '-') {
topRow[i].setHorizontalAlignment('center');
}
}
};

Modification points:
In your script, topRowValues is var topRowValues = topRow.getValues();. In this case, it is a 2-dimensional array. By this, topRowValues[i] == '-' is always false.
topRow is var topRow = spreadsheet.getRange('A1:1');. By this, topRow[i].setHorizontalAlignment('center') occurs an error because topRow[i] is undefined. But, by the above issue, the script in the if statement is not run.
About var topRowValues = topRow.getValues() and topRowValues.length, in this case, topRowValues.length is 1. By this, the for loop is looped only one time.
About spreadsheet.getRange('A1:1'), in this case, all cells of a row are retrieved.
When setHorizontalAlignment is used in a loop, the process cost will become high.
When these points are reflected in your script, it becomes as follows.
Modified script:
function CenterAlignAllDashes() {
// Ref: https://stackoverflow.com/a/53678158
const columnIndexToLetter_ = index => (a = Math.floor(index / 26)) >= 0 ? columnIndexToLetter_(a - 1) + String.fromCharCode(65 + (index % 26)) : "";
var sheet = SpreadsheetApp.getActiveSheet();
var topRow = sheet.getRange(1, 1, 1, sheet.getLastColumn());
var topRowValues = topRow.getValues()[0];
var ranges = [];
for (let i = 0; i < topRowValues.length; i++) {
if (topRowValues[i] == '-') {
ranges.push(`${columnIndexToLetter_(i)}1`);
}
}
sheet.getRangeList(ranges).setHorizontalAlignment("center");
}
When this script is run, first, the values are retrieved from the 1st row and create the range list. And, the alignment is changed using the range list.
References:
getLastColumn()
getValues()
getRangeList(a1Notations)
setHorizontalAlignment(alignment) of Class RangeList

Try this:
function CenterAlignAllDashes() {
const sh = SpreadsheetApp.getActiveSheet();
sh.getRange(1, 1, 1, sh.getLastColumn()).getValues().flat().forEach((v, i) => {
if (v == "-") {
sh.getRange(1, i + 1).setHorizontalAlignment("center");
}
});
}

Related

Moving rows to another sheet based on certain criteria in google apps script

I am working on creating a script that needs to push rows from one sheet of a google workbook to another based on how the row is categorized by an entry in another column. This needs to be also adaptable to have it push to a different google workbook in some cases in the future. I have tried multiple iterations of the following script and it will pull the rows over and then updated background colors, but it is just iterating through all the data and pulling over everything instead of just those rows with an "X" in the relevant column.
What I'd like it to do is pull only those on the "Feedback" tab which are not set to green as the cell color in column F, and those with an "X" in column F, then to have it set the cell to green once it has pulled so that it won't pull the same information next time I run the script. I want to then have it do the same thing using column G.
Here is a test doc I have been testing with.
https://docs.google.com/spreadsheets/d/1JLyEuVijQ8MvfOKrtbRD_YKmRDnTCxf7qCSw9Ggty_Y/edit#gid=384324173
This is the code I have currently:
function oneFeedback() {
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ss = sss.getSheetByName("Feedback");
var s = ss.getSheetName();
var data = ss.getDataRange().getValues();
var bostab = sss.getSheetByName("1");
if(s !== "Feedback"){
Browser.msgBox("This option isn't available for this sheet.")
}
else
{
for(var i = 2; i < data.length; i++){
if(ss.getRange(i+1,6).getBackground !== "#d9ead3"){
if(ss.getRange(i+1,6) !== ""){
var values = ss.getRange(i+1,1,1,5).getValues();
bostab.insertRowBefore(2);
bostab.getRange(2,2,1,5).setValues(values).setFontColor("#000000");
ss.getRange(i+1,6).setBackground("#d9ead3");
}
}
Browser.msgBox("Complete")
}
}
}
The script is set to run from selecting a menu item in the "Extras" menu that is being created using the "Code.gs" script on this doc.
Modification points:
In your script, getBackground of ss.getRange(i+1,6).getBackground might be getBackground().
When getValues() and setValues() are used in a loop, the process cost will become high. Ref (Author: me)
Only column "F" is used.
When these points are reflected in your script, how about the following modification?
Modified script:
function oneFeedback() {
// Ref: https://stackoverflow.com/a/53678158
const columnIndexToLetter_ = index => (a = Math.floor(index / 26)) >= 0 ? columnIndexToLetter_(a - 1) + String.fromCharCode(65 + (index % 26)) : "";
// Retrieve source sheet.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = ss.getSheetByName("Feedback");
if (!srcSheet) Browser.msgBox("This option isn't available for this sheet.");
// Retrieve source values.
const range = srcSheet.getDataRange();
const [header, ...values] = range.getValues();
const [, ...backgrounds] = range.getBackgrounds();
// Create an object for putting to destination sheets.
const offset = 5; // This is from your question.
const dstSheets = header.splice(offset);
const obj = dstSheets.reduce((o, e) => (o[e] = [], o), {});
const res = values.reduce((o, r, i) => {
dstSheets.forEach((h, j) => {
const idx = offset + j;
if (r[idx] == "X" && backgrounds[i][idx] != "#d9ead3") {
o[h].push(r);
o.ranges.push(`${columnIndexToLetter_(idx)}${i + 2}`);
}
});
return o;
}, { ...obj, ranges: [] });
// Put values to destination sheets.
dstSheets.forEach(e => {
const v = res[e];
if (v.length > 0) {
const dstSheet = ss.getSheetByName(e);
dstSheet.getRange(dstSheet.getLastRow() + 1, 1, v.length, v[0].length).setValues(v);
}
});
// Set background colors of source cells.
if (res.ranges.length == 0) return;
srcSheet.getRangeList(res.ranges).setBackground("#d9ead3");
}
When this script is run, I thought that your goal might be able to be achieved.
References:
reduce()
forEach()
setBackground(color) of Class RangeList

How to search columns for a specific value and move the target row to the top?

I am trying to search column E for a cell starting with "X". I then want to move that entire row up to the top.
This is what I've created so far, using IndexOf:
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var Today = spreadsheet.getSheetByName("Today");
var TodayList = Today.getRange('E:E').getValues();
var i = TodayList.indexOf("X", 0);
Today.moveRows(Today.getRow(i), 1);
In your situation, how about the following modification?
In the case of Array.prototype.indexOf(), the values cannot be directly checked from the 2-dimensional array. But, in your situation, I thought that the 1st character can be directly checked using the index as follows.
Modified script:
function myFunction() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var Today = spreadsheet.getSheetByName("Today");
var TodayList = Today.getRange('E1:E' + Today.getLastRow()).getValues();
TodayList.forEach(([e], i) => {
if (e[0] == "X") {
var row = i + 1;
Today.moveRows(Today.getRange(`${row}:${row}`), 1);
}
});
}
When this script is run, the values are retrieved from column "E". And, each cell value is checked from the retrieved values. When the 1st character of the cell value is "X", the row is moved to the 1st row.
In this modification, the lower rows are moved to the upper row. If you want to do this with the reverse, please modify it as follows.
From
TodayList.forEach(([e], i) => {
if (e[0] == "X") {
var row = i + 1;
Today.moveRows(Today.getRange(`${row}:${row}`), 1);
}
});
To
var len = TodayList.length;
var offset = 0;
TodayList.reverse().forEach(([e], i) => {
if (e[0] == "X") {
var row = len - i + offset;
Today.moveRows(Today.getRange(`${row}:${row}`), 1);
offset++;
}
});
References:
forEach()
moveRows(rowSpec, destinationIndex)
Find X rows and move to top
function funko() {
const ss = SpreadsheetApp.getActive();
const tsh = ss.getSheetByName("Today");
const tvs = tsh.getRange(1, 1, tsh.getLastRow(), tsh.getLastColumn()).getValues();
let a = [];
let d = 0;
tvs.forEach((r, i) => {
if (r[4] == "X") {
a.push(r)
tsh.deleteRow(i + 1 - d++);
}
});
tsh.insertRowsBefore(1,a.length)
a.reverse();
tsh.getRange(1,1,a.length,a[0].length).setValues(a);
}

' getValues() ' collecting only one value when trying to remove empty cells

My idea is to remove the diacricts from the values and send them to Column B, but also send the original values to Column C of the spreadsheet.
Column A on Spreadsheet:
ábéécÓ
Á
ábéécÓ
Á
My code:
var defaultDiacriticsRemovalMap = [
{'base':'A', 'letters':'\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'},
{'base':'AA','letters':'\uA732'},
{'base':'AE','letters':'\u00C6\u01FC\u01E2'},
{'base':'AO','letters':'\uA734'},
{'base':'AU','letters':'\uA736'},
{'base':'AV','letters':'\uA738\uA73A'},
{'base':'AY','letters':'\uA73C'},
{'base':'B', 'letters':'\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181'},
{'base':'C', 'letters':'\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E'},
{'base':'D', 'letters':'\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0'},
{'base':'DZ','letters':'\u01F1\u01C4'},
{'base':'Dz','letters':'\u01F2\u01C5'},
{'base':'E', 'letters':'\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E'},
{'base':'F', 'letters':'\u0046\u24BB\uFF26\u1E1E\u0191\uA77B'},
{'base':'G', 'letters':'\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E'},
{'base':'H', 'letters':'\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D'},
{'base':'I', 'letters':'\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197'},
{'base':'J', 'letters':'\u004A\u24BF\uFF2A\u0134\u0248'},
{'base':'K', 'letters':'\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2'},
{'base':'L', 'letters':'\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780'},
{'base':'LJ','letters':'\u01C7'},
{'base':'Lj','letters':'\u01C8'},
{'base':'M', 'letters':'\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C'},
{'base':'N', 'letters':'\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4'},
{'base':'NJ','letters':'\u01CA'},
{'base':'Nj','letters':'\u01CB'},
{'base':'O', 'letters':'\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C'},
{'base':'OI','letters':'\u01A2'},
{'base':'OO','letters':'\uA74E'},
{'base':'OU','letters':'\u0222'},
{'base':'OE','letters':'\u008C\u0152'},
{'base':'oe','letters':'\u009C\u0153'},
{'base':'P', 'letters':'\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754'},
{'base':'Q', 'letters':'\u0051\u24C6\uFF31\uA756\uA758\u024A'},
{'base':'R', 'letters':'\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782'},
{'base':'S', 'letters':'\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784'},
{'base':'T', 'letters':'\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786'},
{'base':'TZ','letters':'\uA728'},
{'base':'U', 'letters':'\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244'},
{'base':'V', 'letters':'\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245'},
{'base':'VY','letters':'\uA760'},
{'base':'W', 'letters':'\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72'},
{'base':'X', 'letters':'\u0058\u24CD\uFF38\u1E8A\u1E8C'},
{'base':'Y', 'letters':'\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE'},
{'base':'Z', 'letters':'\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762'},
{'base':'a', 'letters':'\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250'},
{'base':'aa','letters':'\uA733'},
{'base':'ae','letters':'\u00E6\u01FD\u01E3'},
{'base':'ao','letters':'\uA735'},
{'base':'au','letters':'\uA737'},
{'base':'av','letters':'\uA739\uA73B'},
{'base':'ay','letters':'\uA73D'},
{'base':'b', 'letters':'\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253'},
{'base':'c', 'letters':'\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184'},
{'base':'d', 'letters':'\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A'},
{'base':'dz','letters':'\u01F3\u01C6'},
{'base':'e', 'letters':'\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD'},
{'base':'f', 'letters':'\u0066\u24D5\uFF46\u1E1F\u0192\uA77C'},
{'base':'g', 'letters':'\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F'},
{'base':'h', 'letters':'\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265'},
{'base':'hv','letters':'\u0195'},
{'base':'i', 'letters':'\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131'},
{'base':'j', 'letters':'\u006A\u24D9\uFF4A\u0135\u01F0\u0249'},
{'base':'k', 'letters':'\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3'},
{'base':'l', 'letters':'\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747'},
{'base':'lj','letters':'\u01C9'},
{'base':'m', 'letters':'\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F'},
{'base':'n', 'letters':'\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5'},
{'base':'nj','letters':'\u01CC'},
{'base':'o', 'letters':'\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275'},
{'base':'oi','letters':'\u01A3'},
{'base':'ou','letters':'\u0223'},
{'base':'oo','letters':'\uA74F'},
{'base':'p','letters':'\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755'},
{'base':'q','letters':'\u0071\u24E0\uFF51\u024B\uA757\uA759'},
{'base':'r','letters':'\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783'},
{'base':'s','letters':'\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B'},
{'base':'t','letters':'\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787'},
{'base':'tz','letters':'\uA729'},
{'base':'u','letters': '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289'},
{'base':'v','letters':'\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C'},
{'base':'vy','letters':'\uA761'},
{'base':'w','letters':'\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73'},
{'base':'x','letters':'\u0078\u24E7\uFF58\u1E8B\u1E8D'},
{'base':'y','letters':'\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF'},
{'base':'z','letters':'\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'}
];
var diacriticsMap = {};
for (var i=0; i < defaultDiacriticsRemovalMap .length; i++){
var letters = defaultDiacriticsRemovalMap [i].letters;
for (var j=0; j < letters.length ; j++){
diacriticsMap[letters[j]] = defaultDiacriticsRemovalMap [i].base;
}
}
function Looping() {
var sheet = SpreadsheetApp.getActive().getSheetByName('remove_diacritics'),
range,
values_array;
range = sheet.getRange('A1:A');
var loop = range.getValues().flat().filter(e => e);
sheet.getRange(1, 3).setValue(loop);
var new_values = [];
for (var key of loop) {
var newText = key.replace(/[^\u0000-\u007E]/g, function(a){
return diacriticsMap[a] || a;
});
new_values.push(newText);
}
sheet.getRange(1, 2).setValue(new_values);
}
Column B and C on Spreadsheet return after run the code:
abeecO ábéécÓ
Expected Result in Column B and C on Spreadsheet:
abeecO ábéécÓ
A Á
abeecO ábéécÓ
A Á
I also tried create a loop using but it didn't work:
var loop = range.getValues().filter(function(array){
return array != ''
})
What am I doing wrong that all four values are not collected?
Modification points:
When I saw your 1st submitted quesiton, you are trying to put an array of var loop = range.getValues().flat().filter(e => e); to the sheet with sheet.getRange(1, 3).setValue(loop);. In this case, 1st element of the array loop is put to the cell "C1". I thought that this is the reason of your issue. And also, at var loop = range.getValues().flat().filter(e => e);, 2 dimensional array is converted to 1 dimensional array. In this case, it it is required to modify as follows.
From
range = sheet.getRange('A1:A');
var loop = range.getValues().flat().filter(e => e);
sheet.getRange(1, 3).setValue(loop);
To
range = sheet.getRange('A1:A' + sheet.getLastRow());
var loop = range.getValues().filter(([a]) => a.toString() != "");
sheet.getRange(1, 3, loop.length, 1).setValues(loop);
By this modification, the filtered values of loop are put to the column "C".
When I saw your latest question, the same situation as the above situation can be seen. I think that it is required to modify your latest script like the above one. But, from your showing sample input and output situations, I thought that when the cell value of column "A" is empty, it might be required to put the empty.
When these points are reflected in your script, it becomes as follows.
Modified script:
In this case, please modify Looping() as follows.
function Looping() {
var sheet = SpreadsheetApp.getActive().getSheetByName('remove_diacritics');
var range = sheet.getRange('A1:A' + sheet.getLastRow());
var loop = range.getValues();
var new_values = [];
for (var key of loop) {
var value = key[0];
if (value != "") {
var newText = value.replace(/[^\u0000-\u007E]/g, function (a) {
return diacriticsMap[a] || a;
});
new_values.push([newText, value]);
} else {
new_values.push(["", ""]);
}
}
sheet.getRange(1, 2, new_values.length, new_values[0].length).setValues(new_values);
}
Or, you can also the following modified script.
function Looping() {
var sheet = SpreadsheetApp.getActive().getSheetByName('remove_diacritics');
var values = sheet.getRange('A1:A' + sheet.getLastRow()).getValues();
var new_values = values.map(([v]) => [v.toString() != "" ? v.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a) : "", v]);
sheet.getRange(1, 2, new_values.length, new_values[0].length).setValues(new_values);
}
When these modified scripts are used, your expected result is obtained. And, in this modification, when the cell value of column "A" is empty, the empty values are put to the columns "B" and "C".
If you want to skip the empty rows of the column "A", please modify var loop = range.getValues(); in the above 2 scripts as follows.
function Looping() {
var sheet = SpreadsheetApp.getActive().getSheetByName('remove_diacritics');
var range = sheet.getRange('A1:A' + sheet.getLastRow());
var loop = range.getValues().filter(([a]) => a.toString() != "");
var new_values = [];
for (var key of loop) {
var newText = key[0].replace(/[^\u0000-\u007E]/g, function (a) {
return diacriticsMap[a] || a;
});
new_values.push([newText, key[0]]);
}
sheet.getRange(1, 2, new_values.length, new_values[0].length).setValues(new_values);
}
Or
function Looping() {
var sheet = SpreadsheetApp.getActive().getSheetByName('remove_diacritics');
var values = sheet.getRange('A1:A' + sheet.getLastRow()).getValues();
var new_values = values.flatMap(([v]) => v.toString() != "" ? [[v.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a), v]] : []);
sheet.getRange(1, 2, new_values.length, new_values[0].length).setValues(new_values);
}
References:
setValue(value)
setValues(values)
map()
Getting all of column one
Using ranges like A1:A is not useful because it returns nulls from lastrow to maxrows which need to be filtered out which is just a waste of time.
function Looping() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName('Sheet0');
const vs = sheet.getRange('A1:A' + sheet.getLastRow()).getValues();
Logger.log(JSON.stringify(vs));
}
Execution log
5:43:28 PM Notice Execution started
5:43:27 PM Info [["ábéécÓ"],["Á"],["ábéécÓ"],["Á"]]//2D array
5:43:29 PM Notice Execution completed
Original Data:
A
ábéécÓ
Á
ábéécÓ
Á

Google Sheets Apps Script - set all blank cells in a column to zero

I am a novice when it comes to macros or Google Sheets Apps Script. I'm trying to write a Google Sheets macro to reformat data periodically exported from a website. So far I've figured out most of it, but I'm getting stuck trying to find all blank cells in certain columns (ignoring the header row) and set them to zero. Here's what I have so far:
function _1() {
var spreadsheet = SpreadsheetApp.getActive();
var k = 2;
var j = spreadsheet.getLastRow();
var column = 10;
for (var i = k; i = j; i++){
cell = spreadsheet.getRange(i,column);
if (cell.isBlank()) {
cell.setValue(0);
}
}
}
This returns the following error:
Exception: The parameters (String,number) don't match the method signature for SpreadsheetApp.Spreadsheet.getRange.
I believe this means the getRange function is expecting an input of A1 style cell location, but I'm not certain. I also don't know how to convert to one. Finally I'm not sure that the script will work once I've fixed this. Any help would be appreciated.
Modification points:
I think that the reason of your error of The parameters (String,number) don't match the method signature for SpreadsheetApp.Spreadsheet.getRange. is due to that you are using Class Spreadsheet with var spreadsheet = SpreadsheetApp.getActive();. Class Spreadsheet has no method of getRange(row, column).
In your for loop, (var i = k; i = j; i++) is required to be modified. When you want to modify, please modify to (var i = k; i <= j; i++).
But, in your script, setValue is used in the loop. In this case, the process cost will be high.
When these points are reflected to the sample script, it becomes as follows.
Sample script:
function _1() {
var sheet = SpreadsheetApp.getActiveSheet();
var ranges = sheet
.getRange("J2:J" + sheet.getLastRow())
.getDisplayValues()
.flatMap(([v], i) => v == "" ? ["J" + (i + 2)] : []);
sheet.getRangeList(ranges).setValue(0);
}
In this script, at first, the values are retrieved from the column "J". And, check each cell and retrieve the a1Notations as an array. And then, the value 0 is put to the a1Notations.
If your script is directly modified, it becomes as follows.
function _1() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var k = 2;
var j = spreadsheet.getLastRow();
var column = 10;
for (var i = k; i <= j; i++) {
var cell = spreadsheet.getRange(i, column);
if (cell.isBlank()) {
cell.setValue(0);
}
}
}
If you want to use var spreadsheet = SpreadsheetApp.getActive();, you can also use the following modification.
function _1() {
var spreadsheet = SpreadsheetApp.getActive();
var k = 2;
var j = spreadsheet.getLastRow();
for (var i = k; i <= j; i++) {
cell = spreadsheet.getRange("J" + i);
if (cell.isBlank()) {
cell.setValue(0);
}
}
}
References:
getActive()
getActiveSheet()
getRange(a1Notation) of Class Spreadsheet
getRange(row, column) of Class Sheet
function zero() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const vs = sh.getRange(2, 10, sh.getLastRow() - 1).getValues();
vs.forEach(e => {
if (e[0] == '') {
e[0] = 0;
}
});
sh.getRange(2, 10, vs.length, 1).setValues(vs).setNumberFormat('0.#####');
}

Script for Google sheet to change a cells value based on another cells value (in a column range)

Here is the scenario:
Column E in my Googlesheet has a dropdown list of Yes and No. Everytime the user answers No, I want the corresponding cell in Column G to have the words "Not Applicable". But if user answers Yes, I want that cell in G to have another dropdown list of Yes and No.
I tried to build on the script that I got from this thread:
Google Sheets formula to change a cells value based on another cells value
It's almost perfect, but I can't make it to work for a range (an entire column, preferrably). Any advice would be appreciated :)
Since I wasn't getting any success trying to tweak it for my own use, here's a copy code from the mentioned thread:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getActiveSheet()
var nota=e.range.getA1Notation()
if(nota=="E10"){
var val=e.range.getValue()
if(val=="Levy"){
s.getRange("E11").setDataValidation(null)
s.getRange("E11").setValue("Monthly")
}
else{
s.getRange('E11').clearContent()
var cell = s.getRange('E11');
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['Triannual', 'Quarterly']).build();
cell.setDataValidation(rule);
}}}
And here's my dumb attempt:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getActiveSheet()
var nota=e.range.getA1Notation()
if(nota=="E2:E500"){
var val=e.range.getValue()
if(val=="No"){
s.getRange("G2:G500").setDataValidation(null)
s.getRange("G2:G500").setValue("Not Applicable")
}
else{
s.getRange('G2:G500').clearContent()
var cell = s.getRange('G2:G500');
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['Yes','No']).build();
cell.setDataValidation(rule);
}}}
You need to loop a range of cells, which is why the original script isn't working. .getValue() returns a single cell, you can't have a range (as in your edited script).
This script will look at the entire page and loop it each time. This is preferable because you don't have to keep data in order. In other words, you can jump around Column E and mark things "Yes" or "No" as they come up. Blank cells are ignored.
function addValidation() {
// Get the spreadsheet and active sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Get the data as an Array you can iterate and manipulate
var data = sheet.getDataRange().getValues();
// Store a rule to use for the Data Validation to be added if ColE == "Yes"
var rule = SpreadsheetApp.newDataValidation().requireValueInList(["Yes", "No"]).build();
// Loop the sheet
for(var i=0; i<data.length; i++) {
// Test ColE. Note that the array is 0-indexed, so A=0, B=2, etc...
// To change which columns you're testing, change the second value.
if(data[i][4] == "Yes") {
// If it's "Yes," add the Data Validation rule to Col G for that row.
// Note that .getRange() is _not_ 0 indexed, which is why you need `i+1` to get the correct row
sheet.getRange(i+1, 7).clear().setDataValidation(rule);
// If ColE == "No," mark ColG as "Not Applicable"
} else if(data[i][4] == "No") {
sheet.getRange(i+1, 7).clearDataValidations().setValue("Not Applicable");
}
}
}
Also note that this will change values as you change Col E. So, if you change a "Yes" to a "No," Col G will be changed to "Not Applicable."
for (var i = 0; i < 5000; i++) {
function checkData() {
if(SpreadsheetApp.getActiveSheet().getRange("E" + i).getValue() == "No"){
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Not Applicable');
}
else{
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Applicable');
}
}
}
Hope this works for you:)
Btw getting the range of 5000 rows will be VERY slow! Here is another way you can do it faster!
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tsSheet = ss.getSheetByName("YOUR SHEET NAME AT THE BOTTOM OF THE PAGE");
var tsRows = parseInt(tsSheet.getLastRow());
for (var i = 0; i < tsRows; i++) {
function checkData() {
if(SpreadsheetApp.getActiveSheet().getRange("E" + i).getValue() == "No"){
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Not Applicable');
}
else{
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Applicable');
}
}
}
EDIT:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tsSheet = ss.getSheetByName("YOUR SHEET NAME AT THE BOTTOM OF THE PAGE");
var tsRows = parseInt(tsSheet.getLastRow());
for (var i = 0; i < tsRows + 1; i++) {
function checkData() {
if(SpreadsheetApp.getActiveSheet().getRange("E" + i).getValue() == "No"){
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Not Applicable');
}
else{
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Applicable');
}
}
}