Reputation: 776
I have an array of columns that I want to keep. I've got that code below:
//Keep only columns user wants.
if(keepColumnsArray != ""){
for (var col = sourceShtLC; col > 0; col--) {
if (keepColumnsArray.indexOf(col) == -1) {
// This isn't a keeper, delete it
destSht.deleteColumn(col);
}
}
}
What I'd like to do now is arrange the columns following the order the keepColumnsArray
has them.
Samples:
var keepColumnsArray = [3,2,1,4,5]
Using the above sample I want column 3 to be the first column, column 2 to be the second, column 1 to be the 3rd, column 4 to be the 4th and column 5 to be the 5th.
Current Order:
The order I want it. As you can see it's the same order the array is in.
Solution: Rather than deleting the columns first I used code from the accepted answer to move the columns I want to keep to the front. In this case Columns 1 through 5 I kept and then I deleted the rest because all that was left were columns I did not need. Here is my final code.
//Use order of array to reorder columns and then delete the rest of the columns
var offset = keepColumnsArray.length;
destSht.insertColumns(1, offset);
keepColumnsArray.forEach(function(e, i) {
destSht.getRange(1, (e + offset), destSht.getLastRow(), 1).copyTo(destSht.getRange(1, i + 1));
});
destSht.deleteColumns(offset + 1, sourceShtLC); //Keep only columns user wants.
Upvotes: 1
Views: 511
Reputation: 201378
var keepColumnsArray = [3,2,1,4,5]
.
1, 2, 3, 4, 5
to 3, 2, 1, 4, 5
.If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
In this case, moveColumns
is used. The flow of this script is as follows.
moveColumns
.function myFunction() {
var keepColumnsArray = [3,2,1,4,5];
var obj = keepColumnsArray.reduce(function(ar, e, i) {
ar.push({from: i + 1, to: e});
return ar;
}, []);
obj.sort(function(a, b) {return a.to < b.to ? -1 : 1});
var sheet = SpreadsheetApp.getActiveSheet();
obj.forEach(function(o) {
var columnSpec = sheet.getRange(1, o.from);
if (o.from != o.to) sheet.moveColumns(columnSpec, o.to);
for (var j = 0; j < obj.length; j++) {
if (obj[j].from < o.from) obj[j].from += 1;
}
});
}
In this case, each column is copied with the order of keepColumnsArray
using a temporal sheet, and put the arranged columns to the original sheet.
function myFunction() {
var keepColumnsArray = [3,2,1,4,5];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var temp = ss.insertSheet("temp");
sheet.activate();
keepColumnsArray.forEach(function(e, i) {
sheet.getRange(1, e, sheet.getLastRow(), 1).copyTo(temp.getRange(1, i + 1));
});
temp.getDataRange().copyTo(sheet.getRange(1, 1));
ss.deleteSheet(temp);
}
From OP's comment, In this sample script, the columns are inserted and put the arranged columns.
Instead of creating a temp sheet can we not add 5 columns to the beginning and then copy them to those new columns?
function myFunction() {
var keepColumnsArray = [3,2,1,4,5];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var offset = keepColumnsArray.length;
sheet.insertColumns(1, offset);
keepColumnsArray.forEach(function(e, i) {
sheet.getRange(1, e + offset, sheet.getLastRow(), 1).copyTo(sheet.getRange(1, i + 1));
});
sheet.deleteColumns(offset, offset);
}
Upvotes: 3
Reputation: 10345
Problem
Solution
First, add logic that filters and sorts your values. One of the possible algorithms is as follows: map source such that each row is mapped such that each cell is cell by order index from source and filter columns such that its index is a keep index.
var input = [3,2,1,4,5];
var initial = [
['Column1','Column2','Column3','Column4','Column5','Column6','Column7'],
['2first','2second','2third','2fourth','2fifth','2sixth','2seventh'],
];
function filterAndReorder (source,order) {
return source
.map(function(row,r){
return row.map(function(cell,c){
return source[r][order[c]-1];
})
.filter(function(cell,c){
return cell !== undefined;
});
})
}
var output = filterAndReorder(initial,input);
console.log(output);
Then, use the fact that setValues()
accepts 2D Array
and replaces Range
contents:
var lrow = destSht.getLastRow();
var range = destSht.getRange(1,1,lrow,5);
var inputVals = range.getValues();
var keepColumnsArray = []; //obtain the keep Array somehow;
var outputVals = filterAndReorder(inputVals,keepColumnsArray);
var range.setValues(outputVals);
Notes
keepColumnsArray
is an Array
so the != ""
is redundant (unless you actually expect it to be an empty string in which case I would suggest rewriting the logic that outputs the Array
- it will save you at least 1 op + save you debug time in the future).deleteColumn
is an I/O and thus should at least be performed in batch.deleteColumns()
References
Upvotes: 2