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.
Related
This is my first time using google spreadsheets, and I'm trying to accomplish something in the functions. I know it's javascript (A language I'm not entirely familiar with). I'm trying to take a range from two tables, and get the intersection location of each, and fill in missing values for rows that already should exist.
For example, assuming the following two sheets:
Sheet1
+-----------+----------+--------+---------+
| Fruit | Color | Weight | isApple |
+-----------+----------+--------+---------+
| Banana | Yellow | 3 | no |
| Orange | Orange | 3 | no |
| Apple | Red | 2 | yes |
| Pineapple | Brownish | 5 | no |
+-----------+----------+--------+---------+
Sheet2
+-----------+----------+--------+---------+
| Fruit | Color | Weight | isApple |
+-----------+----------+--------+---------+
| Banana | | | |
| Apple | | | |
| Pear | | | |
| Watermelon| | | |
+-----------+----------+--------+---------+
I want to find the intersections of the Fruit row, and fill in the color, weight, and isApple, of each one we know.
I wrote something I felt confident should work to get the intersection of range1, and it returns an empty array for some reason. When I test this in Apps Script Editor, it seems to work fine.
//assuming range1 = Sheet1!A2:A5 and range2=Sheet2!A2:A5
function intersection(range1, range2) {
var i = 0;
var j = 0;
var matches = new Array();
while(i < range1.length){
if(range2.toString().includes(range1[i].toString())){
matches.push(i);
}
i++
}
return matches;
}
I would expect this to return an array of [0,2] since the 0th element Banana, and the 1st element Apple from Sheet1, exist in sheet 2.
I would then use that data to fill in the rows for Apple, and Banana from the information in Sheet2.
I'm not at that second part yet, since I can't seem to get the sheet to even find the intersection.
My end goal expected output would be that Sheet 2 is changed to:
Sheet2
+-----------+----------+--------+---------+
| Fruit | Color | Weight | isApple |
+-----------+----------+--------+---------+
| Banana | Yellow | 3 | no |
| Apple | Red | 2 | yes |
| Pear | | | |
| Watermelon| | | |
+-----------+----------+--------+---------+
I believe your goal as follows.
You want to achieve the result from "Sheet1" and "Sheet2" as shown in your question.
You want to achieve this using the custom function.
For this, how about this answer?
Modification points:
In your script, I thought that you are using the custom function of =intersection(Sheet1!A2:A5,Sheet2!A2:A5). In this case, the arguments of range1 and range2 of function intersection(range1, range2) { are [["Banana"],["Orange"],["Apple"],["Pineapple"]] and [["Banana"],["Apple"],["Pear"],["Watermelon"]], which are 2 dimensional arrays, respectively. Namely, the values on the sheet are sent to the arguments. In order to achieve your goal, I would like to propose to use the custom function like =intersection(Sheet1!A2:D5,Sheet2!A2:A5). By this, the values from "Sheet1" can be used in the custom function.
In your script, the value of [0,2] is retrieved as matches. This is the indexes of range1. But in this case, it is required to also know the indexes matching to range2. This has already mentioned in your question. In this case, how about the following flow?
In order to achieve your goal, I would like to propose the following flow.
From the values of "Sheet1", create an object for searching values of the column "A".
From the values of "Sheet2", create an result array using the created object.
The sample script reflected above flow is as follows.
Sample script:
Please copy and paste the following script, and out the custom function =intersection(Sheet1!A2:D5,Sheet2!A2:A5) to the cell "B2" of "Sheet2". By this, the result that you showed at the bottom of your question is obtained.
function intersection(values1, values2) {
const obj = values1.reduce((o, [a, ...bcd]) => Object.assign(o, {[a]: bcd}), {});
return values2.map(([a]) => obj[a] ? obj[a] : [""]);
}
Result:
References:
Custom Functions in Google Sheets
reduce()
Object.assign()
Spread syntax (...)
map()
I am pulling data from tabs in a sheet and putting them into a single tab using "compilation.sort(6,true);"
It pulls the data in, but it would be fantastic if there was a way to add rows during the sort, instead of afterwards. Is there a way to insert rows, or even a header, between unique values of the sort?
I have tried: "compilation.sort(6,true).insertRowAfter(i,1);" without success.
What I Have:
Row 1 | Row 2 | Row 3
--------- ------- -------
Pasta | Sauce | 3
Pasta | Sauce | 4
Pasta | Sauce | 5
Pizza | Sauce | 10
Pizza | Sauce | 11
Pizza | Sauce | 12
Spaghetti | Sauce | 9
What I am looking for:
Row 1 | Row 2 | Row 3
--------- ------- -------
Pasta | Sauce | 3
Pasta | Sauce | 4
Pasta | Sauce | 5
Pizza | Sauce | 8
Pizza | Sauce | 11
Pizza | Sauce | 12
Spaghetti | Sauce | 9
For the active sheet you can use
function runSample2() {
/**
* #type {conditionCallback}
*/
var cb;
cb = function(row, i, values) {
// Returns true if it's not the first row,
// the first cell of a row does not equal one of previous row
// and there is no an empty row before
return (
values[i - 1] &&
values[i - 1][0] !== row[0] &&
values[i - 1].join('') !== ''
);
};
var sheet = SpreadsheetApp.getActiveSheet();
insertRowBeforeByCondition_(sheet, cb);
}
function insertRowBeforeByCondition_(sheet, condition) {
var dataRange = sheet.getDataRange();
var values = dataRange.getValues();
var i = values.length;
while (i-- > 0)
if (condition(values[i], i, values)) sheet.insertRowBefore(i + 1);
return sheet;
}
Based on the snippet.
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.
I have a big Google SpreadSheet document that stores some data and I need to use Google SpreadSheet REST API to retrieve particular rows from it.
Let's say we have the following test data:
ID | Name | Date
-----------------
1 | Erik | 07.06.2017
2 | Anna | 07.06.2017
3 | Kirk | 07.06.2017
4 | Erik | 06.06.2017
5 | Anna | 06.06.2017
6 | Kirk | 06.06.2017
....
I need to retrieve rows with the latest date such as:
1 | Erik | 07.06.2017
2 | Anna | 07.06.2017
3 | Kirk | 07.06.2017
How can I achieve this ?
EDIT:
From the official doc I've found that I can retrieve a range by the following request:
GET https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId/values/Sheet1!A1:D5
But this not suitable for me because I need filtering by max date :(
you can use event object that tracks every change in sheet to track last modified and 'copy' it to some fixed possiion in sheet like I did in this short video..
you have to paste this in your Tools -> Script Editor
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet();
var rng = e.range;
var ix = rng.getRow();
var X = s.getRange( ix, 1, 1, 3 );
s.getRange( 3, 5, 1, 3 ).copyTo( s.getRange( 4, 5 ) ); // SECOND LAST TO BUTTOM
s.getRange( 2, 5, 1, 3 ).copyTo( s.getRange( 3, 5 ) ); // SECOND LAST TO BUTTOM
X.copyTo( s.getRange( 2, 5 ) ); // LAST ON TOP!
}
.. and then you can pull your data via REST like:
GET https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId/values/Sheet1!E2:G4
hope that helps :)
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'....