I am working towards updating a sample of code seen at: Merge cells with same words Provided by @Tanaike
I am essentially trying to do the same thing as the sample c
If I understand correctly you want to transform a row of cells that looks like this:
Jan | Jan | Feb | Feb | Feb | Mar | Apr | Apr | Apr |
into this:
Jan | Feb | Mar | Apr |
If so, I can help!
I think part of your issue comes from your call to getRange(row, column, numRows, numColumns).
In a comment you say var start = 6
is the start row, but you put it in the column spot. Not sure what you intended, but it might be more clear to have a startRow
and a startCol
variable. Eg,
var startRow = 1;
var startCol = 1;
// Later...
ss.getRange(startRow, startCol, 1, ss.getLastColumn())
Calling Range.getValues()
in a Google Script returns a two dimensional "array-of-arrays." With the example cells I provided you would get something like:
data = [['Jan', 'Jan', 'Feb', 'Feb', 'Feb', 'Mar', 'Apr', 'Apr', 'Apr']]
Since we're just dealing with one row, we can take the first item of this outer array and call that data, simplifying things a bit. So I would do:
var data = ss
.getRange(startRow, startCol, 1, ss.getLastColumn())
.getValues()
.filter(String)[0];
Which gives you:
data = ['Jan', 'Jan', 'Feb', 'Feb', 'Feb', 'Mar', 'Apr', 'Apr', 'Apr']
The next bit of code deals with counting how many times each month is duplicated. With our nice, one-dimensional array we can make the code a little simpler:
data.forEach(function(e) {
c[e] = c[e] ? c[e] + 1 : 1;
});
Here we're looping over the array data
, dealing with each entry "e
" in turn. (e
will be "Jan", then "Jan" again, then "Feb"). We're storing the counts in an object, c
which starts off blank and will look like this when we're finished:
c = {Feb: 3.0, Apr: 3.0, Jan: 2.0, Mar: 1.0}
The ?
and :
stuff is fancy JavaScript ternary syntax, which is basically saying:
c[e] = c[e] ? c[e] + 1 : 1;
[-----] [-----][-------][---]
| | | |
| v | |
(1) "have we already created an entry in c for this month e (eg, "Jan")?
| | |
| v |
(2) "if so, COUNT is the current value (look it up) plus 1
| |
| v
(3) | "if not, COUNT is 1"
|
v
(4) "store the COUNT we found in c"
The final step could look like this:
data.forEach(function(e) {
if (e != k) {
ss.getRange(startRow, startCol + offset, 1, c[e]).merge();
offset += c[e];
}
k = e;
});
Again, things are a tiny bit simpler because data
is now a 1d array instead of a 2d array.
function mergeMonths() {
var startRow = 1;
var startCol = 1;
var c = {};
var k = "";
var offset = 0;
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("BlockingChart1");
// Get data from sheet
var data = ss
.getRange(startRow, startCol, 1, ss.getLastColumn())
.getValues()
.filter(String)[0];
// Count duplicates
data.forEach(function(e) {
c[e] = c[e] ? c[e] + 1 : 1;
});
// Merge duplicate cells
data.forEach(function(e) {
if (e != k) {
ss.getRange(startRow, startCol + offset, 1, c[e]).merge();
offset += c[e];
}
k = e;
});
}
One final tip: The logger is super helpful for seeing what's going on in your code. When you're testing your code I would stick lines like:
Logger.log("data: %s", data);
and
Logger.log("e: %s", e);
All over the place, then check the Google Scripts log (view > logs) to understand what your variables are at different points.