3

I am working with Google Sheets and Google Apps Scripting. I have used .getRange().getValues to grab user emails from a Sheet.

Example Array Received: [[user1, , ], [user2, user3, ], [user4, user5, user6]]

As you can see, I have a potential of up to three users per row (inner array). However, some of those cells are empty resulting in empty values in the array. I am then feeding each inner array into .addEditors() which throws an error due to the empty user.

I know I can run through each array and delete the empties and then push that new array into .addEditors() but it would be ugly, and very inefficient. I don't have enough experience to know how to develop a more elegant way.

Could someone help me understand the how and the why to solve this issue in as efficient a manner as possible? Thanks.

Note: Though it seems like the .filter(Boolean) solution might work, I can only get it to work for a single array, not for an array within an array.

var myFilterArray = myArray.filter(Boolean);

    arr.forEach(function(x){
      return x.filter(Boolean);
    });

I cannot get it to return the modified array if greater than one deep.

2
  • Possible duplicate of Remove all falsy values from an array Commented Apr 22, 2019 at 15:06
  • I checked that out and can't get that solution to work. The values collected appear to be falsy but instead are being treated as 0. Thanks though as this would have been the easiest solution. Commented Apr 22, 2019 at 16:26

3 Answers 3

7

I know I can run through each array and delete the empties... thats pretty much your only options. There are methods that make your code look cleaner but behind the scenes something is going to have to loop through the array.

Here is an example using Array.map() and Array.filter()

let data = [["bob", , ], ["jake", "john", ""], ["joe", "henry", "morgan"]];
let newData = data.map(x => {
  return x.filter(j => j)
})
console.log(newData);

Using ES5 syntax

var data = [["bob", , ], ["jake", "john", ""], ["joe", "henry", "morgan"]];
var newData = data.map(function(x) {
  return x.filter(function(j) {if (j) return j})
})
console.log(newData);

Sign up to request clarification or add additional context in comments.

4 Comments

If it's known that the unwanted (empty) slots are always at the ends of the array, it would be possible to simply truncate the arrays by setting .length.
@Isaac - This looks like the exact code that I need. However, I'm trying to run just this code as you wrote it but I keep getting an error on the second line. It's telling me that I need a semicolon. Can you help me understand how this code works so that I might be able to place it into apps script without the error?
Possibly because your browser doesn't support array function syntax, or because you aren't transpiling es5 to es6. Try using es5 syntax instead.
Perfect! Yes, it was the syntax. So, in trying to understand... .map creates a duplicate of the array and .filter keeps only those elements with value. How does the if (j) return j work? It is just saying "because there is a value, return that value?"
1

If You have following type of array then we can rid of empty data using filter method.

var data=[["user1", , ], ["user2", "user3", ], ["user4", "user5", "user6"]];

data.filter(a => a.filter( b => b.length>0));

2 Comments

Thank you, but I couldn't not get this code to work in the apps script IDE.
I realized that the issue for me here is your code is ES6 syntax and I am using ES5. Thanks for your help.
0

Just out of curiosity I ran these four functions 10 times each on 3 columns and 1000 rows of data. Partially, I was interested in learning more about these array methods because I've just began to use them. So I'm not expert at them for sure.

The code:

function removeFalsies1() {
  var start=new Date();
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getActiveSheet();
  var rg=sh.getDataRange();
  var vA=rg.getValues();
  var vU=[];
  var cnt=0;
  for(var i=1;i<vA.length;i++){
    for(var j=0;j<vA[i].length;j++) {
      cnt++;
      if(vA[i][j]) {
        vU.push(vA[i][j]);
      }
    }
  }
  var end=new Date();
  return Utilities.formatString('1,%s',seconds_(start,end));
}

function removeFalsies2() {
  var start=new Date();
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getActiveSheet();
  var rg=sh.getDataRange();
  var vA=rg.getValues();
  var cnt=0;
  var vU=[];
  vA.forEach(function(r,i,A){ 
    if(i>0) {
      for(var n=0;n<A[i].length;n++){
        var rA=[];
        cnt++;
        if(A[i][n] && i>0){
          vU.push(A[i][n]);
        }
      }
    }
    return rA;
  });
  var end=new Date();
  return Utilities.formatString('2,%s',seconds_(start,end));
}

function removeFalsies3() {
  var start=new Date();
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getActiveSheet();
  var rg=sh.getDataRange();
  var vA=rg.getValues();
  var cnt=0;
  var vU=[];
  vA.forEach(function(r,i,A){if(i>0){r.forEach(function(rix,ix,r){if(rix){vU.push(rix);}cnt++;})}});
  var end=new Date();
  return Utilities.formatString('3,%s',seconds_(start,end));
}

function removeFalsies4() {
  var start=new Date();
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getActiveSheet();
  var rg=sh.getDataRange();
  var vA=rg.getValues();
  var cnt=0;
  var vU=[];
  vA.map(function(r,i) {if(i>0){return r.filter(function(rix){if(rix){vU.push(rix);}cnt++;})}});
  var end=new Date();
  return Utilities.formatString('4,%s',seconds_(start,end));
}

The Data:

The single digit numbers refer the last digit in the function names. enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.