简体   繁体   中英

Google Apps Script - ForEach in Range

For each row in a range, I'd like to add one or several entries to an array, depending on the value of an int, in one of the row's column. Eg if my row is :

Val1   1

I want to push an object {Val1,'US'} to my array. On the other hand, if my row is :

Val1   2

I want to push two objects : {Val1,'FR'}, {Val1,'DE'} to my array. I can't figure out why the following code doesn't work :

  var range = sheet.getRange("A2:B");
  var results = range.getDisplayValues();
  var array = [];

  results.forEach(function(row){          

    switch(row[1]){
      case '1' :               
        row[1] = "US";        
        array.push(row);                        
        break;
      case '2' :
        row[1] = "FR";
        array.push(row);      
        row[1] = "DE";
        array.push(row);     
        break; 
      case '3' :
        var entry1 = row;
        var entry2 = row;
        entry1[1] = "UK";
        entry2[1] = "SW";
        array.push(entry1);      
        array.push(entry2);      
        break;            
    }           
  });    
return array;

This returns me twice "DE" and twice "SW". I tried a different way in case three, to make sure that the problem was not with variable reference, but the same thing occurs. Could it be because of the way I'm looping on values ? Why is it behaving this way ?

Thank you for your help.

It's because JS pushes a variable that is then modified, so the value is replaced everywhere.

Try pushing directly like this, without storing:

  var range = sheet.getRange("A2:B");
  var results = range.getDisplayValues();
  var array = [];

  results.forEach(function(row){          

    switch(row[1]){
      case '1' :               
        array.push([row[0],"US"]);                        
        break;
      case '2' :
        array.push([row[0],"FR"]);      
        array.push([row[0],"DE"]);     
        break; 
      case '3' :
        array.push([row[0],"UK"]);      
        array.push([row[0],"SW"]);      
        break;            
    }           
  });    
return array;

You are modifying "row" in place, without making a copy. Ie, you're putting a reference to "row" (the same array) into several places, and then modifying "row" again afterwards - thus overwriting your original changes.

To avoid the problem, you can use Array.slice() to make a copy of row, like this:

var range = sheet.getRange("A2:B");
var results = range.getDisplayValues();
var array = [];

results.forEach(function(row) {
  switch(row[1]) {
    case '1' :
      // No copy necessary, since you're only using it once              
      row[1] = "US";
      array.push(row);
      break;
    case '2' :
      // Copy not necessary for the first use
      row[1] = "FR";
      array.push(row);
      // Copy here, since you will modify it again
      row = row.slice();
      row[1] = "DE";
      array.push(row);
      break; 
    case '3' :
      // Make one extra copy
      var entry1 = row;
      var entry2 = row.slice();
      entry1[1] = "UK";
      entry2[1] = "SW";
      array.push(entry1);
      array.push(entry2);
      break;
  }
});
return array;

Mind you, for the case where you only have two elements in the arrays you push, building new arrays for each case (as shown in another answer) is probably better. And if I was going to have this in production code where performance wasn't very critical, I'd likely make a copy for every modification instead of the just-when-you-need-it variant above. The way I've written it above demonstrates the necessary copies (to make it easier to understand the point), but it is much easier to make it incorrect with changes than if you just copy everything defensively.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM