Caution: my English is far from perfect. (Русский тоже не всегда хорош).

Tuesday, 17 January 2012

maybeComma

I once made a small invention: the simplest way to join values in 
a collection using comma as a separator:

    result = '';
    maybeComma = '';
    for (val : collection) {
      result += maybeComma + val;
      maybeComma = ',';
    }

If collection = [1, 2, 3], then result = '1,2,3'.

I invented this almost 10 year ago, and it was useful many times. There are 
environments, like shell scripts, where there is no Arrays.toString method. 
And even C++, at the times when I programmed on this language, didn't have any
such "join" function in the standard library (that's why I needed to invent it; 
BTW, it's interesting, does C++ have join today... quick googling makes 
impression it doesn't...).

I never saw more simple implementation. All the implementations I saw have 
an IF inside the loop:
  
    result = '';
    for (i = 0; i < collection.length; i++) {
      if (i > 0) {
         result += ',';
      }
      result += collection[i];
    }

Here we also needed to change the "for each" construct to a "for by variable i", 
to determine if we are at the first iteration or not.

The maybeComma solution does not depend on the iteration construct at all.
Therefore it is easier to adopt. For example joining two collections.
In the maybeComma approach we just copy/paste the loop without rethinking
the logic, it always works the same:

    result = '';
    maybeComma = '';
    for (val : collectionA) {
      result += maybeComma + val;
      maybeComma = ',';
    }
    for (val : collectionB) {
      result += maybeComma + val;
      maybeComma = ',';
    }

In the IF approach we again need to change the control constructs by 
introducing a boolean flag:

    result = '';
    oneDone = false;
    for (i = 0; i < collectionA.length; i++) {
      if (oneDone) {
         result += ',';
      }
      result += collectionA[i];
      oneDone = true;
    }
    for (i = 0; i < collectionB.length; i++) {
      if (oneDone) {
         result += ',';
      }
      result += collectionB[i];
      oneDone = true;
    }

As far as I remember this understanding of how to avoid logic by switching to 
different data values came to me from ThinkingForth - the idea of how to use
the maybeComma variable to avoid the IF in the solution was a result of conscious 
attempt to apply what is taught in this book.