Given list like:
List<String> names = Lists.newArrayList("George", "John", "Paul", "Ringo")
I'd like to transform it to a string like this:
George, John, Paul and Ringo
I can do it with rather clumsy StringBuilder
thing like so:
String nameList = names.stream().collect(joining(", "));
if (nameList.contains(",")) {
StringBuilder builder = new StringBuilder(nameList);
builder.replace(nameList.lastIndexOf(','), nameList.lastIndexOf(',') + 1, " and");
return builder.toString();
}
Is there a bit more elegant approach? I don't mind using a library if needed.
NOTES:
for
loop with an index, but I am not looking for such a solutionAs you already did most of it I would introduce a second method "replaceLast" which is not in the JDK for java.lang.String so far:
import java.util.List;
import java.util.stream.Collectors;
public final class StringUtils {
private static final String AND = " and ";
private static final String COMMA = ", ";
// your initial call wrapped with a replaceLast call
public static String asLiteralNumeration(List<String> strings) {
return replaceLast(strings.stream().collect(Collectors.joining(COMMA)), COMMA, AND);
}
public static String replaceLast(String text, String regex, String replacement) {
return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement);
}
}
You might change the delimiters and params as well. Here the test for your requirements so far:
@org.junit.Test
public void test() {
List<String> names = Arrays.asList("George", "John", "Paul", "Ringo");
assertEquals("George, John, Paul and Ringo", StringUtils.asLiteralNumeration(names));
List<String> oneItemList = Arrays.asList("Paul");
assertEquals("Paul", StringUtils.asLiteralNumeration(oneItemList));
List<String> emptyList = Arrays.asList("");
assertEquals("", StringUtils.asLiteralNumeration(emptyList));
}
I'm not sure how elegant this is, but it works. The annoying part is that you have to reverse the List
.
List<String> list = Arrays.asList("George", "John", "Paul", "Ringo");
String andStr = " and ";
String commaStr = ", ";
int n = list.size();
String result = list.size() == 0 ? "" :
IntStream.range(0, n)
.mapToObj(i -> list.get(n - 1 - i))
.reduce((s, t) -> t + (s.contains(andStr) ? commaStr : andStr) + s)
.get();
System.out.println(result);
However, I think the best solution is this.
StringBuilder sb = new StringBuilder();
int n = list.size();
for (String string : list) {
sb.append(string);
if (--n > 0)
sb.append(n == 1 ? " and " : ", ");
}
System.out.println(sb);
It's clear, efficient, and obviously works. I don't think Stream
s are a good fit for this problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With