Best Loop Idiom for special casing the last element

Dougnukem picture Dougnukem · Jun 23, 2010 · Viewed 16.8k times · Source

I run into this case a lot of times when doing simple text processing and print statements where I am looping over a collection and I want to special case the last element (for example every normal element will be comma separated except for the last case).

Is there some best practice idiom or elegant form that doesn't require duplicating code or shoving in an if, else in the loop.

For example I have a list of strings that I want to print in a comma separated list. (the do while solution already assumes the list has 2 or more elements otherwise it'd be just as bad as the more correct for loop with conditional).

e.g. List = ("dog", "cat", "bat")

I want to print "[dog, cat, bat]"

I present 2 methods the

  1. For loop with conditional

    public static String forLoopConditional(String[] items) {
    
    String itemOutput = "[";
    
    for (int i = 0; i < items.length; i++) {
        // Check if we're not at the last element
        if (i < (items.length - 1)) {
            itemOutput += items[i] + ", ";
        } else {
            // last element
            itemOutput += items[i];
        }
    }
    itemOutput += "]";
    
    return itemOutput;
     }
    
  2. do while loop priming the loop

    public static String doWhileLoopPrime(String[] items) {
    String itemOutput = "[";
    int i = 0;
    
    itemOutput += items[i++];
    if (i < (items.length)) {
        do {
            itemOutput += ", " + items[i++];
        } while (i < items.length);
    }
    itemOutput += "]";
    
    return itemOutput;
    }
    

    Tester class:

    public static void main(String[] args) {
        String[] items = { "dog", "cat", "bat" };
    
        System.out.println(forLoopConditional(items));
        System.out.println(doWhileLoopPrime(items));
    
    }
    

In the Java AbstractCollection class it has the following implementation (a little verbose because it contains all edge case error checking, but not bad).

public String toString() {
    Iterator<E> i = iterator();
if (! i.hasNext())
    return "[]";

StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
    E e = i.next();
    sb.append(e == this ? "(this Collection)" : e);
    if (! i.hasNext())
    return sb.append(']').toString();
    sb.append(", ");
}
}

Answer

finnw picture finnw · Jun 24, 2010

I usually write it like this:

static String commaSeparated(String[] items) {
    StringBuilder sb = new StringBuilder();
    String sep = "";
    for (String item: items) {
        sb.append(sep);
        sb.append(item);
        sep = ",";
    }
    return sb.toString();
}