问题
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