Search |
||
List SeparatorsPosted by brucechapman on March 25, 2008 at 5:58 PM PDT
In his Disturbing Thoughts from a Developing Mind blog, fellow kiwi Mark Derricutt discusses a situation where new for loops don't provide enough power for a particular case. (And yes this blog has been sitting drafted but unpublished for ages :( ) The case in point is building a String from the concatenation of a List of Strings with some separator between them, in this case a semi-colon. The problem is expressed as "append the separator after each element, except the last one". What seems to have evaded Mark and his commenters is that the problem can be expressed differently. If you restate the problem as "append the separator before each item except the first one" then you are one step away from what seems to me to be an elegant solution, at least compared to the others offered. That final step is to realise that "except the first one" can be rephrased as except the first one in which case you prepend nothing". Applying this to the relevant section of Mark's code yields
StringBuilder sb = new StringBuilder();
String separator = "";
for (String listenerClassName : data.TEST_LISTENERS) {
if (listenerClassName != null && !"".equals(listenerClassName)) {
sb.append(separator).append(listenerClassName);
separator = ";";
}
}
There is a more OOish solution, which is to have a (tiny) class thus
public Class Separator {
private String next = "";
private String separator;
public Separator(String separator) {
this.separator = separator;
}
public String get() {
String result = next;
next = separator;
return result;
}
}
which returns an empty string the first time get() is called, then the configured value thereafter. With this we can code the loop as
StringBuilder sb = new StringBuilder();
Separator sep = new Separator(";");
for (String listenerClassName : data.TEST_LISTENERS) {
if (listenerClassName != null && !"".equals(listenerClassName)) {
sb.append(sep.get()).append(listenerClassName);
}
}
So how do you tackle this problem? »
Related Topics >>
Programming Comments
Comments are listed in date ascending order (oldest first)
Submitted by cayhorstmann on Fri, 2008-03-28 08:12.
Or, in Scala, data.TEST_LISTENERS.mkString(";")
Submitted by tackline on Fri, 2008-03-28 10:19.
data.TEST_LISTENERS = Collections.emptyList();
sb.delete(sb.length()-separator.length(), sb.length());
Ugly.
Also note that 1.5 has String.isEmpty.
Submitted by tackline on Fri, 2008-03-28 10:20.
data.TEST_LISTENERS = Collections.emptyList();
sb.delete(sb.length()-separator.length(), sb.length());
Ugly.
Also note that 1.5 has String.isEmpty.
Submitted by danielrohe on Fri, 2008-03-28 10:51.
String separator = ...;
List strings = ...;
StringBuilder builder = new StringBuilder();
for (Iterator iter = strings.iterator(); iter.hasNext(); ) {
builder.append(iter.next());
if (iter.hasNext()) builder.append(separator);
}
Greetings,
Daniel
Submitted by jkeatley on Fri, 2008-03-28 12:18.
I encounter this quite a bit, so this is how I handle it:
StringBuilder sb = new StringBuilder();
boolean fFirst = true;
for (String listenerClassName: data.TEST_LISTENERS)
{
if (!fFirst)
sb.append(";");
sb.append(listenerClassName);
fFirst = false;
}
Submitted by kennardconsulting on Sun, 2008-03-30 20:26.
Slightly cleaner than using fFirst - use StringBuilder as the flag:
StringBuilder sb = new StringBuilder();
for (String listenerClassName: data.TEST_LISTENERS)
{
if (sb.length() > 0)
sb.append(";");
sb.append(listenerClassName);
}
Submitted by gwvantreese on Tue, 2008-03-25 20:46.
StringBuilder sb = new StringBuilder();
String separator = ";";
for (String listenerClassName : data.TEST_LISTENERS) {
if (listenerClassName != null && !"".equals(listenerClassName)) {
sb.append(listenerClassName).append(separator);
}
}
sb.deleteCharAt(sb.length() - 1);
Submitted by trcorbin on Wed, 2008-03-26 13:08.
I do it the same way you do, though I hadn't thought of using the OOish way.
This comes up fairly often, so it's idiomatic for me.
Submitted by aberrant on Wed, 2008-03-26 17:21.
I've done this more times then I can count. I ended up writing StringUtil.join(Collection, String seperator). This seems like the natural counterpart to split(). Any reason this isn't in String?
Submitted by alexlamsl on Sat, 2008-03-29 08:24.
If we think out-of-the-box a little bit:
public static final String join(final String separator, final String firstElement, final String ... elements) {
final StringBuilder sb = new StringBuilder(firstElement);
if (elements != null) {
for (final String element : elements) {
sb.append(separator).append(element);
}
}
return sb.toString();
}
Submitted by alexlamsl on Sat, 2008-03-29 08:42.
Then for the core of the problem:
public static String join(final String separator, final Iterable elements) {
final StringBuilder sb = new StringBuilder();
for (final String element : elements) {
sb.append(separator).append(element);
}
return sb.substring(separator.length()).toString();
}
Using the boolean flag to skip the first element is probably a better overall solution to the generalised form of this problem, especially if the join operation is expensive or not quite undo-able.
But for the case of Strings I'd prefer the illustrated solution more :-)
Submitted by alexlamsl on Sat, 2008-03-29 08:44.
Iterable<String> of course - forgotten to escape my characters :-/
|
||
|
|