Google sheets, sort function - function

I want to auto-sort through the script editor in Google Sheets. I have in my Google Sheets several columns:
+--------+------------+-------+--------+------------+
| Region | Mag | Comp | Region | Mag |
+--------+------------+-------+--------+------------+
| A | MIKA | TRUE | A | MIKA |
| B | KALO | FALSE | B | NOKA |
| C | MINA | FALSE | C | South-East |
| D | North | TRUE | D | North |
| B | NOKA | FALSE | B | KALO |
| C | South-East | FALSE | C | MINA |
+--------+------------+-------+--------+------------+
I would like to match the two columns (Region, Mag) on the left with the two columns (Region, Mag) on the right, so in the end I would have my comparison column (which has a formula like =exact(string1,string2)) with TRUEs only.
I want to have a kind of button so that my two columns (Region, Mag) on the right of Comp could sort themselves.
I had this script, thanks to #JPV
function onOpen() {
SpreadsheetApp.getUi().createMenu('Sort').addItem('Sort Col D and E', 'sort').addToUi();
}
function sort() {
var ss = SpreadsheetApp.getActiveSheet();
var srange = ss.getRange('A2:B7').getValues();
var trange = ss.getRange('D2:E7');
var trangeVal = trange.getValues();
var returnarr = [];
for (var i = 0, ilen = trangeVal.length; i < ilen; i++) {
for (var j = 0, jlen = srange.length; j < jlen; j++) {
if (trangeVal[i][0] == srange[j][0] && trangeVal[i][1] == srange[j][1]) {
returnarr[j] = trangeVal[i];
}
}
}
trange.setValues(returnarr);
}
But seems not working and throwing an error like "Cannot convert Array to Object[][]"
Any help please!
Again thanks to #JPV

Ok. Maybe this script will help you ?
function onOpen() {
SpreadsheetApp.getUi().createMenu('Sort').addItem('Sort Col D and E', 'sort').addToUi();
}
function sort() {
var ss = SpreadsheetApp.getActiveSheet();
var srange = ss.getRange('A2:B7').getValues();
var trange = ss.getRange('D2:E7');
var trangeVal = trange.getValues();
var returnarr = [];
for (var i = 0, ilen = trangeVal.length; i < ilen; i++) {
for (var j = 0, jlen = srange.length; j < jlen; j++) {
if (trangeVal[i][0] == srange[j][0] && trangeVal[i][1] == srange[j][1]) {
returnarr[j] = trangeVal[i];
}
}
}
trange.setValues(returnarr);
}
Note: this will only work if the values in D&E are somewhere to be found in A&B. Also be aware of the fact that his will overwrite the values in D&E.
Test sheet here

Related

Script to search for multiple unread labels in Gmail threads at once

I have the following structure of labels
+------------+------------+---------------+
| label | sub-label | sub-sub-label |
+------------+------------+---------------+
| 01-fruit | | |
| | 01-apples | |
| | | green |
| | | red |
| | 02-oranges | |
| | | red |
| | | orange |
| 02-veggies | | |
| | 01-peppers | |
| | | green |
| | | red |
+------------+------------+---------------+
The script in use is:
function mail2Sheets() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('newRec'); //get the sheet
var freshLabel = GmailApp.getUserLabelByName("00-fresh"); // in the end, add this label
const query = "label:unread" + " label:01-fruit";
var foundThreads = GmailApp.search(query);
var newReceipts = [];
for (var i = 0; i < foundThreads.length; i++) {
+++++++ SOME CODE HERE +++++++
}
}
if(!foundThreads.length) return; // if there are no unread ones, do nothing.
sheet.getRange(SpreadsheetApp.getActiveSheet().getLastRow()+1,2,newReceipts.length,newReceipts[0].length).setValues(newReceipts); //write to sheet
GmailApp.markThreadsRead(foundThreads); // mark "foundThreads" as read
freshLabel.addToThreads(foundThreads); // add label "00-fresh" to "foundThreads"
GmailApp.refreshThreads(foundThreads); // refresh "foundThreads" for changes to show
}
I can successfully search for a single label like: const query = "label:unread" + " label:01-fruit";
Also.
Although I have GmailApp.refreshThreads(foundThreads); the Execution never completes.
Instead it shows Status Running
TO RECAP
How can I make the query search at the same time for multiple labels like
"label:unread" + " label:00-fruit/01-apples/red"
AND
"label:unread" + " label:02-veggies/01-peppers/red"
Also. How can the Status Running issue be fixed?
" " which is a space is used as AND operator.
OR and {} can be used as OR operator.
Using above operators, your goal can be achieved.
When you want to search the mails with label:unread and label:00-fruit/01-apples/red, please use the search query as follows.
label:unread label:00-fruit/01-apples/red
When you want to search the mails with label:unread and label:00-fruit/01-apples/red or label:02-veggies/01-peppers/red, please use the search query as follows.
label:unread (label:00-fruit/01-apples/red OR label:02-veggies/01-peppers/red)
or
label:unread {label:00-fruit/01-apples/red label:02-veggies/01-peppers/red}
Reference:
Search operators you can use with Gmail

Time Driven Conditional Updates on Google Spreadsheets

I would like to update the given date [reset day] on weekly periods.
During this update if weekly attendance will also reset to 0 and if its value is less than 2 Attendance points will decrease by 8 points.
Example Initial Sheet
Name | Attendance Point | Weekly Attendance | Reset Day
--------------------------------------------------------------
Jack | 12 | 0 | 13/09/2018
Jacob | 23 | 0 |
Emily | 12 | 1 |
Rick | 11 | 2 |
Rob | 21 | 3 |
Desired Update
Name | Attendance Point | Weekly Attendance | Reset Day
--------------------------------------------------------------
Jack | 4 | 0 | 20/09/2018
Jacob | 15 | 0 |
Emily | 4 | 0 |
Rick | 11 | 0 |
Rob | 21 | 0 |
Sample base sheet
https://docs.google.com/spreadsheets/d/1khPC5r2p0b1srsEGka3fl-GAl6nHACaVR0Cf31cqA1o/edit?usp=sharing
Thanks in advance
function resetCells() {
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet');
var range = ss.getDataRange().offset(1, 0, ss.getLastRow() - 1);
var values = range.getValues().map(function(e) {
return e[0] ? [false, e[1], e[2], e[3], e[4] + 1, e[5]] : e;
});
range.setValues(values);
}
Update Function
function weekDays() {
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet').getRange('F2').setValue(new Date())
}
I solved the problem with this snippet of script
function weekDays() {
var sd = SpreadsheetApp.getActive().getSheetByName('Sheet').getRange('F2').setValue(new Date())
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet');
var range = ss.getDataRange().offset(1, 0, ss.getLastRow() - 1);
var values = range.getValues().map(function(e) {
if (Number(e[4]) < 2 && Number(e[2] >= 8) ) {
return e[1] ? [e[0], e[1], Number(e[2]) - 8, e[3], 0, e[5]] : e;
} else if (Number(e[4]) < 2 && Number(e[2]) < 8) {
return e[1] ? [e[0], e[1], 0, e[3], 0, e[5]] : e;
} else {
return e[1] ? [e[0], e[1], e[2], e[3], 0, e[5]] : e;
}
});
range.setValues(values);
}

Google Sheets script - find matching tuples and copy data between sheets

I have 2 sheets in the same spreadsheet, call them sheet1 and sheet2. In each sheet, every row describes some hardware component and its properties. The point of sheet2 is to eventually replace the outdated sheet1.
Simple example, (real sheets are hundreds of lines long):
sheet1:
componentId | prop1 | prop2 | prop3 | isvalid
---------------------------------------------
1 | x1 | y1 | z1 | yes
2 | x1 | y2 | z3 | yes
3 | x2 | y1 | z1 | yes
sheet2:
componentId | quantity | prop1 | prop2 | prop3 | prop4 | isvalid
----------------------------------------------------------------
15 | 4 | x1 | y1 | z1 | w1 | TBD
23 | 25 | x3 | y3 | z2 | w1 | TBD
33 | 3 | x1 | y2 | z3 | w2 | TBD
The final column "isValid" in sheet1 has been manually populated. What I would like to do is write a script that iterates through sheet1, producing a tuple of the property values, and then looks for matching property value tuples in sheet2. If there is a match, I would like to copy the "isValid" field from sheet1 to the "isValid" field in sheet2.
What I have so far is the following, but I am experiencing a error "The coordinates or dimensions of the range are invalid" - see comment in code below showing where error is. And, the entire thing feels really hacky. Was hoping someone could maybe point me in a better direction? Thanks in advance.
function arraysEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
function copySheetBasedOnRowTuples(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('sheet 1 name');
var sheet2 = ss.getSheetByName('sheet 2 name');
s2data = sheet2.getDataRange().getValues()
s1data = sheet1.getDataRange().getValues()
for( i in s1data ){
sheet1Tuple = [ s1data[i][1], s1data[i][2], s1data[i][3] ]
// Now go through sheet2 looking for this tuple,
// and if we find it, copy the data in sheet1 column 4
// to sheet2 column 6 for the rows that matched (i and j)
for ( j in s2data){
sheet2Tuple = [ s2data[j][2], s2data[j][3], s2data[j][4] ]
if ( arraysEqual(sheet1Tuple, sheet2Tuple) ){
// ERROR HAPPENS HERE
sheet2.getRange(j, 6).setValue( sheet1.getRange( i, 4 ).getValue() )
}
}
}
}
The reason of error is the start number between array and range. The index of array starts from 0. The row and column of getRange() start from 1. So how about this modification?
From :
sheet2.getRange(j, 6).setValue( sheet1.getRange( i, 4 ).getValue() )
To :
sheet2.getRange(j+1, 7).setValue( sheet1.getRange( i+1, 5 ).getValue() )
If this was not useful for you, please tell me. I would like to modify.

Sort Array by highest value google script

I have the following spreadsheet:
| Name | Rating |
| John | 2000 |
| Jane | 50 |
| Bill | 3000 |
| Sam | 500 |
I get the data for the spreadsheet in the following way:
mySheet.getDataRange().getValues();
My goal is to print the array from highest rating to lowest rating. How can I do that?
EDIT: I probably should mention I am aware of the sort function: However, the issue there is it sorts as a string, not a number. Which means that 60 will show above 2000 because it starts with a 6.
You need to pass a comparator function to the sort() method.
function sortDescending() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
var values = range.getValues();
values.sort(function(a, b){
return b[1] - a[1]; //sorts by the 2nd element in a row
});
Logger.log(values);
}
Note that I skipped the header row and didn't include it in the list of values to sort. Hope this helps.

Create new row for each not empty column

I'm trying to convert an Excel macro to Google Apps Script. I would like to create a new row on a specific sheet for each not empty column in Google Spreadsheets.
My Inputsheet looks like the following:
ID | Inrellevant Column | Givenmoney | Takenmoney | Othermoney
1 | Data1 | 100 | 200 | 300
2 | Data2 | 400 | | 500
I want to create a new row in another sheet for each not empty cell, so the desired Outputsheet would be:
ID | Inrellevant Column | Moneycode | Amount
1 | Data1 | Givenmoney | 100
1 | Data1 | Takenmoney | 200
1 | Data1 | Othermoney | 300
2 | Data2 | Givenmoney | 400
2 | Data2 | Othermoney | 500
I tried the following:
Outputsheet.getRange('A2').offset(0, 0, Inputsheet.length).setValues(Inputsheet);
However I can't see to create a loop to create new rows for each not empty column.
Hoi Fred, assuming you want the output to appear from the top left cell onwards in the sheet 'Outputsheet', try this code:
function myFunction() {
var ss = SpreadsheetApp.getActive(),
source = ss.getSheetByName('Inputsheet'),
target = ss.getSheetByName('Outputsheet'),
arr = [
["ID", "Header 2nd col", "Moneycode", "Amount"]
],
data = source.getDataRange().getValues(),
headers = data[0];
data.splice(1)
.forEach(function (r) {
r.forEach(function (c, i) {
if (!isNaN(parseFloat(c)) && isFinite(c) && i > 1) {
arr.push([r[0], r[1], headers[i], c])
}
})
})
target.getRange(1, 1, arr.length, arr[0].length).setValues(arr);
}
See this example sheet where you can run the above script from the menu 'My Menu'....