1

I'm trying to write a custom Google Spreadsheets function in AppsScript that will take an array ("range") of arbitrary dimensions and return the unique values in a single column. The function takes an optional argument transpose that should sort the output by rows instead of columns.

I've got this semi-working, but the transpose method is only working on square arrays:

function GETUNIQUES(range, transpose) {
  traspose = transpose || !0;
  if (transpose) {
    range = range.map(function(col, i) {
      return range.map(function(row) {
        return row[i];
      });
    });
  }
  
  var flat = [];
  var clean = [];
  for (i = 0; i < range.length; i++) {
    for (j = 0; j < range[i].length; j++) {
      flat.push(range[i][j]);
    }
  }

  for (i = 0; i < flat.length; i++) {
    flat[i] = String(flat[i]);
    if (flat[i].length && clean.indexOf(flat[i].trim()) < 0) {
      clean.push(flat[i].trim());
    }
  }
  return clean;
}

Could someone help me with a solution for the transpose method that follows row order without truncating results?

Rubén
  • 34,714
  • 9
  • 70
  • 166
jonaz
  • 2,096
  • 1
  • 17
  • 30

2 Answers2

1

Transpose does not work with Array#map(), because the length could be not the wanted length.

Transpose with Array#forEach()

The forEach() method executes a provided function once per array element.

var range = [[0, 1], [2, 3], [4, 5]];

range = function (array) {
    var r = [];
    array.forEach(function (a, i) {
        a.forEach(function (b, j) {
            r[j] = r[j] || [];
            r[j][i] = b;
        });
    });
    return r;
}(range);

document.write('<pre>' + JSON.stringify(range, 0, 4) + '</pre>');

Transpose with Array#reduce()

The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

var range = [[0, 1], [2, 3], [4, 5]];

range = range.reduce(function (r, a, i) {
    a.forEach(function (b, j) {
        r[j] = r[j] || [];
        r[j][i] = b;
    });
    return r;
}, []);

document.write('<pre>' + JSON.stringify(range, 0, 4) + '</pre>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

from the Sheets Product Forum:

=ARRAYFORMULA({array1;array2;array3})

...will merge multiple ranges in one view-only column then:

=UNIQUE(ARRAYFORMULA({A2:A5; B3:B7; C10}))

or

=TRANSPOSE(UNIQUE(ARRAYFORMULA({A2:A5; B3:B7; C10})))
Bryan P
  • 5,031
  • 3
  • 30
  • 44