Why does Array.indexOf doesn't work?

1,139 views
Skip to first unread message

Martín Perucki

unread,
Dec 26, 2020, 8:30:10 AM12/26/20
to Google Apps Script Community
Hi
I just started learning with Apps Scripts so I am more than a beginner here (I do have some experience in Python, but I am slowly starting to learn JavaScript as well).

For my current project, I want to get all the sheets of the file, and filter some of them if they are specified in the function.
I did some research and found a way I want to test out, but arguments.indexOf appears not to be included in the default methods:



What am I missing here? From my understanding this method is part of the Array class (thus arguments.indexOf should exist if arguments is an array) so I should not need to declare it, right?

Thank you very much for your time.
Looking forward to hear from a hero to save me!
Regards.

Martín Perucki

unread,
Dec 26, 2020, 8:47:55 AM12/26/20
to Google Apps Script Community
I just realized that arguments is actually not an array, so that's why the indexOf was not working.
Still, I am lost because it actually doesn't filter elements as expected...
This is the code:


I would really appreciate if someone could help me figure out how to make it work!
Thank you in advance.

Martín Perucki

unread,
Dec 26, 2020, 8:49:32 AM12/26/20
to Google Apps Script Community
I am very sorry!! None of the images were attached properly.
Appending the last comment (I'd already deleted the previous one from my computer...)

Thanks.
code.png

Alvin Seville

unread,
Dec 26, 2020, 9:20:45 AM12/26/20
to Google Apps Script Community
Why not to use pastebin? :)

Adam Morris

unread,
Dec 26, 2020, 9:29:00 AM12/26/20
to google-apps-sc...@googlegroups.com
Hi there, welcome to js-land!

The arguments keyword is not an array, as you've discovered, but array-like. You can convert it to an array as you have:

const args = Array.from(arguments);

But you don't really need to use that, and it makes for unclear code. It's better to actually pass arguments. Are you looking to pass a variable number of sheet names to the function? That can be accomplished with something called the spread syntax:

function get_all_sheets_except(...exclusions) {
// exclusions is now an array of all the parameters
}

function test () {
get_all_sheets_except('first', 'second');
}

I could write the function that produces what you are looking for, but I notice you are using a nested for loop, but would suggest that you can solve this problem using Array.map and Array.filter. Also, you can use Array.includes instead of indexOf.

Have fun!

Adam




--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-apps-script-community/ed3ade13-cf37-4c8c-a697-303f4b8e9500n%40googlegroups.com.

Adam Morris

unread,
Dec 26, 2020, 9:34:46 AM12/26/20
to google-apps-sc...@googlegroups.com
After sending this I realize that Array.map is normally used like this,

const arr = []
arr.map()

And not like the array.from one put in my code. Don’t want to put you on wild goose chase either!
--

Martín Perucki

unread,
Dec 27, 2020, 12:14:40 AM12/27/20
to Google Apps Script Community
>  alvinse
Thanks for letting me know about https://pastebin.com/ !  
I didn't know about it. I will start using it once my questions about codes keep increasing (pretty soon I guess haha)
Thanks again!

> Adam Morris
Thank you for clear explanation!
It worked when changed the parameters using the Spread Syntax and cleaned the code a little bit more.
This is the current working result:
function GET_ALL_SHEETS_EXCEPT(...exclusions) {
  // This function gets all Sheets of the file, 
  // then removes the specified sheets passed as arguments to the function,
  // and returns the remaining Sheet names as an Array.

  // (...exclusitons) is using Spread Syntax to get the "exclusions" variable passed
  // 01) Get all sheets
  var all_sheets = new Array() // Create an empty array to store all sheets
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();  // Get all sheet objects
  for (var i=0 ; i<sheets.length ; i++) {  // Iterate through the sheet objects array
    all_sheets.push( [ sheets[i].getName() ] )  // Use Array.push() to add an item to the end of an Array
    }

  // 02) Filter from arguments (exclusions)
  var filtered_sheets = [...all_sheets]  // Copying the array (using spread syntax)
  for (var j=0; j<filtered_sheets.length; j++){  // Iterating through each element of the filtered array
    for (var k=0; k<exclusions.length; k++){  // Iterating through each element of the exclusions array
      if (filtered_sheets[j] == exclusions[k]){  // Match if the names are the same
        if (k > -1){  // -1 means "no match found" in Array.indexOf(x)
          var index = filtered_sheets.indexOf(filtered_sheets[j]);  // Get the index of the name matched in the filtered array
          filtered_sheets.splice(index, 1);  // Remove the element from the array
        }else{
          ++k;  // Go to next iteration
        }
      }
    }
  }
  return filtered_sheets 
}

I tried looking for some examples of the Array.map() and Array.filter() but I couldn't figure out how to use it in this case.
It would be awesome to learn that as well to have two different approaches to the same function, so I would appreciate if you could teach me with a simple example focused in this task sir Adam!

Thank you again for your time people, I really appreciate it.
Regards.

Martín Perucki

unread,
Dec 27, 2020, 12:32:03 AM12/27/20
to Google Apps Script Community
Also, I just realized that if I wanted to use a cell range instead of an array of elements this function doesn't work.
I used the spread syntax to get the argument as an array, but what if the input is not an array but a selection of cells?
To make this function work for both cases, how should I split the content of the function based on the parameter type?

Regards!

Adam Morris

unread,
Dec 27, 2020, 3:33:05 AM12/27/20
to google-apps-sc...@googlegroups.com
Okay, this is what I came up with. Note that the first two don’t do exactly what you were looking for. Instead of return an array of names, they actually returns an array of the original sheet objects. The third one does return array of just names.

function getSheetsExcluding1(...excluding) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();

// populate allSheets with allSheet names
var allSheets = [];
for (var index = 0; index < sheets.length; index += 1) {
allSheets.push( sheets[index].getName() );
}

// populate ret array with those that are not sent as parameters

var ret = [];
for (var index = 0; index < allSheets.length; index++) {
var sheetName = allSheets[index];
if (excluding.indexOf(sheetName) == -1) {
ret.push( sheets[index] );
}
}

return ret;
}

function getSheetsExcluding2(...excluding) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets()
// converts the sheets to an array of names
var step1 = sheets.map( (sheet) => sheet.getName() );

// convert to array of boolean as a marker
var step2 = step1.map( (name) => !excluding.includes(name) );

// filter out from original sheets those that have been marked to exclude
var step3 = sheets.filter( (item, index) => step2[index] );

return step3;  
}

function getSheetsExcluding3(...excluding) {
   var ss = SpreadsheetApp.getActiveSpreadsheet();
   var sheets = ss.getSheets();
   return sheets.map( (sheet) => sheet.getName() )
                           .filter( (name) => !excluding.includes(name) );
}



--

Martín Perucki

unread,
Dec 31, 2020, 7:58:19 PM12/31/20
to Google Apps Script Community
Hi Adam

First of all, Happy New Year!
Thank you for your specific examples.
Sorry I couldn't reply sooner.

I noticed things like the Arrow Functions in the getSheetsExcluding2 
and the multi-line function in getSheetsExcluding3, among others,
that are still new to me and make it a little hard to still comprehend how the data 
flows in the example functions. 
I will start over again from tutorials to learn the very core javaScript
language and give them a try again in some time.

I really appreciate your time and help,
and hope you have a very nice 2021!
Regards.

Adam Morris

unread,
Dec 31, 2020, 8:10:42 PM12/31/20
to google-apps-sc...@googlegroups.com
That sounds like time well spent. 
The arrow functions presented there auto return, so the expression after the => ... reads like return ...

The multi-line function is known as stacking. Map, filter returns an array, which has map and filter on them. The use of multi lines is just formatting so that the stacking is explicit

--
Reply all
Reply to author
Forward
0 new messages