How to shuffle every second column with google apps script?

自闭症网瘾萝莉.ら 提交于 2020-04-16 06:09:11

问题


I want to randomize D:E, F:G, H:I, J:K if C is 4 with google apps script.

At the moment I use this inefficient & time-consuming code:

function shuffleAnswers() {
 var arr = [0, 2, 4, 6]; 
 for (var i = 2; i < lastRow()+1; i++)
 {
   var amount = sheet().getRange(i,3).getValue();
   if (amount == 4)
   {
     var source = sheet().getRange(i,4,1,2);
     var column = 4 + arr[(Math.random() * arr.length) | 0];
     var destination = sheet().getRange(i,column,1,2);
     var valuesSource = source.getValues();
     var valuesDestination = destination.getValues();
     source.setValues(valuesDestination);
     destination.setValues(valuesSource);     
   }
 }
 arr = [-2, 0, 2, 4]; 
 for (var i = 2; i < lastRow()+1; i++)
 {
   var amount = sheet().getRange(i,3).getValue();
   if (amount == 4)
   {
     var source = sheet().getRange(i,6,1,2);
     var column = 6 + arr[(Math.random() * arr.length) | 0];
     var destination = sheet().getRange(i,column,1,2);
     var valuesSource = source.getValues();
     var valuesDestination = destination.getValues();
     source.setValues(valuesDestination);
     destination.setValues(valuesSource);     
   }
 }
 arr = [-4, -2, 0, 2]; 
 for (var i = 2; i < lastRow()+1; i++)
 {
   var amount = sheet().getRange(i,3).getValue();
   if (amount == 4)
   {
     var source = sheet().getRange(i,8,1,2);
     var column = 8 + arr[(Math.random() * arr.length) | 0];
     var destination = sheet().getRange(i,column,1,2);
     var valuesSource = source.getValues();
     var valuesDestination = destination.getValues();
     source.setValues(valuesDestination);
     destination.setValues(valuesSource);     
   }
 }

 arr = [-6, -4, -2, 0]; 
 for (var i = 2; i < lastRow()+1; i++)
 {
   var amount = sheet().getRange(i,3).getValue();
   if (amount == 4)
   {
     var source = sheet().getRange(i,10,1,2);
     var column = 10 + arr[(Math.random() * arr.length) | 0];
     var destination = sheet().getRange(i,column,1,2);
     var valuesSource = source.getValues();
     var valuesDestination = destination.getValues();
     source.setValues(valuesDestination);
     destination.setValues(valuesSource);     
   }
 }
}

Do you have an idea? Maybe with range.randomize()? Every row with C=4 should be randomized. The columns for multiple rows should not be changed to the same position.


回答1:


Why so slow?

  • Use of getValues inside the loop slows down the script considerably. Batching up operations is important.

Script Flow:

  • Create a random array of numbers between 1 to 8 like, [[1,2,5,6,3,4,7,8]] and then use those numbers as indexes for the new row.
  • Get all values from the sheet and rearrange only rows where C=4 and set back all values in one shot.

Sample script:

/* Create a Random arrray of numbers from 1 to 8 with couples
 * eg:[1,2,5,6,3,4,7,8]*/
const doubleShuffleFix = (n = 4) => {
  const generator = function*() {//TODO: boilerplate- can be avoided 
    let i = 1;
    yield i;
    while (true) {
      if (i < (n - 1) * 2) {
        yield (i += 2);
      } else {
        break;
      }
    }
  };
  const available = [...generator()];

  //Durstenfeld algo
  for (let i = available.length - 1; i > 0; i--) {
    let rand = Math.floor(Math.random() * i);
    [available[i], available[rand]] = [available[rand], available[i]];
  }
  return available.map(num => [num, ++num]).flat();
};

function shuffleAnswer() {
  const s = SpreadsheetApp.getActive().getSheetByName('Sheet1'),
    rg = s.getRange(2, 3, s.getLastRow() - 1, 9),
    values = rg.getValues();

  rg.setValues(
    values.map(row => {
      if (row[0] === 4) {
        return [4, ...doubleShuffleFix().map(num => row[num])];
      }
      return row;
    })
  );
}

References:

  • Best practices
  • Durstenfeld algorithm


来源:https://stackoverflow.com/questions/60182839/how-to-shuffle-every-second-column-with-google-apps-script

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!