I have this form of a spreadsheet:
A B C D
abc abc abc 1
def ghi jkl 1
mno pqr stu 3
vwx yza bcd 4
mno pqr stu 5
mno pqr stu 5
vwx yza bcd 5
mno pqr st
You can do that inside google-spreadsheets with the UNIQUE
function.
Here is the doc to all available functions.
(You find UNIQUE
in the Filter
category)
Most likely you want to insert into cell E1
:
=UNIQUE(D1:D)
This will populate column E
with the unique values from all of column D
while preserving the order. Furthermore this will dynamically update and reflect all changes made to column D
.
To do that from within google-apps-script:
SpreadsheetApp.getActiveSheet()
.getRange("E1").setFormula("=UNIQUE(D1:D)");
here is a way to do that... probably not the only one but probably not bad...
I added a few logs to see intermediate results in the logger.
function keepUnique(){
var col = 3 ; // choose the column you want to use as data source (0 indexed, it works at array level)
var sh = SpreadsheetApp.getActiveSheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data=ss.getDataRange().getValues();// get all data
Logger.log(data);
var newdata = new Array();
for(nn in data){
var duplicate = false;
for(j in newdata){
if(data[nn][col] == newdata[j][0]){
duplicate = true;
}
}
if(!duplicate){
newdata.push([data[nn][col]]);
}
}
Logger.log(newdata);
newdata.sort(function(x,y){
var xp = Number(x[0]);// ensure you get numbers
var yp = Number(y[0]);
return xp == yp ? 0 : xp < yp ? -1 : 1;// sort on numeric ascending
});
Logger.log(newdata);
sh.getRange(1,5,newdata.length,newdata[0].length).setValues(newdata);// paste new values sorted in column of your choice (here column 5, indexed from 1, we are on a sheet))
}
EDIT :
Following Theodros answer, the spreadsheet formula is indeed an elegant solution, I never think about it but I should !!! ;-)
=SORT(UNIQUE(D1:D))
gives exactly the same result...
Currently, in V8 engine, the easiest way to do this is to use Set:
/**
* @returns {Object[]} Gets unique values in a 2D array
* @param {Object[][]} array2d
* @private
*/
const getUnique_ = array2d => [...new Set(array2d.flat())];
/**
* Gets Values from a column, makes it unique and sets the modified values
* to the next column
* @param {string} sheetName
* @param {number} column Number of the column to uniquify
* @param {number} headers Number of headers
* @returns void
*/
const uniquifyAColumn = (sheetName = 'Sheet1', column = 3, headers = 1) => {
const sh = SpreadsheetApp.getActive().getSheetByName(sheetName),
rg = sh.getRange(1 + headers, column, sh.getLastRow() - headers, 1),
values = rg.getValues(),
uniqueValues = getUnique_(values).map(e => [e]);
rg.offset(0, 1, uniqueValues.length).setValues(uniqueValues);
};
Here's a script for getting a unique list of nonempty values in a column given the Sheet it's on and the header location of the column using an array to store the values and indexOf to find duplicates. You can then write the array wherever you'd like.
headerLocation is a Location object:
var Location = function(sheet, row, col) {
this.sheet = sheet;
this.row = row;
this.col = col;
this.addRow = function() { this.row = this.row + 1; }
this.addCol = function() { this.col = this.col + 1; }
this.getValue = function() { return sheet.getRange(this.row, this.col).getValue(); }
this.toString = function() { return "(" + this.row + "," + this.col + ")"; }
}
This is the function to read the column and return unique values:
/**
* Get unique values in column, assuming data starts after header
* @param {Sheet} sheet - Sheet with column to search
* @param {object} headerLocation - row and column numbers of the column header cell
* @returns {array} list of unique values in column
*/
function getUniqueColumnValues(sheet, headerLocation) {
let startRow = headerLocation.row + 1;
let lastRow = sheet.getLastRow();
let values = [];
for (i = startRow ; i <= lastRow ; i++) {
let value = sheet.getRange(i, headerLocation.col).getValue();
if ((value != "") && (values.indexOf(value) == -1)) {
values.push(value);
}
}
return values;
}
Or, using a Location to find the values:
function getUniqueColumnValues(sheet, headerLocation) {
let values = [];
let searchLocation = new Location(sheet, headerLocation.row + 1, headerLocation.col);
let lastRow = sheet.getLastRow();
while (searchLocation.row <= lastRow) {
let value = searchLocation.getValue();
if (values.indexOf(value) == -1) {
values.push(value);
}
searchLocation.addRow();
}
return values;
}