用逗号分隔列表的最简单方法是什么?

在 Java 中用逗号分隔列表最清楚的方法是什么?

我知道几种方法,但我想知道什么是最好的方法(“最好”意味着最清楚和/或最短,而不是最有效。

我有一个列表,我想循环它,打印每个值。我想在每个项目之间打印一个逗号,但不是在最后一个项目之后(也不是在第一个项目之前)。

List --> Item ( , Item ) *
List --> ( Item , ) * Item

示例解决方案1:

boolean isFirst = true;
for (Item i : list) {
if (isFirst) {
System.out.print(i);        // no comma
isFirst = false;
} else {
System.out.print(", "+i);   // comma
}
}

示例解决方案2-创建一个子列表:

if (list.size()>0) {
System.out.print(list.get(0));   // no comma
List theRest = list.subList(1, list.size());
for (Item i : theRest) {
System.out.print(", "+i);   // comma
}
}

示例解决方案3:

  Iterator<Item> i = list.iterator();
if (i.hasNext()) {
System.out.print(i.next());
while (i.hasNext())
System.out.print(", "+i.next());
}

这些特别对待第一个项目,而可以代替特别对待最后一个项目。

顺便说一句,下面是在 Java 1.6中 List toString 是如何实现的(它继承自 AbstractCollection) :

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(", ");
}
}

它提前退出循环,以避免在最后一项之后使用逗号。顺便说一下: 这是我第一次看到“(这个集合)”; 下面是激怒它的代码:

List l = new LinkedList();
l.add(l);
System.out.println(l);

I welcome any solution, even if they use unexpected libraries (regexp?); and also solutions in languages other than Java (e.g. I think Python/Ruby have an 点缀 function - how is 那个 implemented?).

澄清 : 说到库,我指的是标准的 Java 库。对于其他库,我考虑它们与其他语言一起使用,并且有兴趣了解它们是如何实现的。

EDIT toolkit 提到了一个类似的问题: < a href = “ https://stackoverflow.com/questions/285523/Last-iteration-of-for-loop-in-java”> Java 中增强的 for loop 的最后一次迭代

还有一个: 循环中的最后一个元素是否需要单独处理?

113239 次浏览

In Python its easy

",".join( yourlist )

In C# there is a static method on the String class

String.Join(",", yourlistofstrings)

Sorry, not sure about Java but thought I'd pipe up as you asked about other languages. I'm sure there would be something similar in Java.

StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
if (result.length()>0)
result.append(", ");
result.append(it.next());
}

Update: As Dave Webb mentioned in the comments this may not produce correct results if the first items in the list are empty strings.

I usually use something similar to version 3. It works well c/c++/bash/... :P

for(int i=0, length=list.size(); i<length; i++)
result+=(i==0?"":", ") + list.get(i);
org.apache.commons.lang3.StringUtils.join(list,",");

You can also unconditionally add the delimiter string, and after the loop remove the extra delimiter at the end. Then an "if list is empty then return this string" at the beginning will allow you to avoid the check at the end (as you cannot remove characters from an empty list)

So the question really is:

"Given a loop and an if, what do you think is the clearest way to have these together?"

Based on Java's List toString implementation:

Iterator i = list.iterator();
for (;;) {
sb.append(i.next());
if (! i.hasNext()) break;
ab.append(", ");
}

It uses a grammar like this:

List --> (Item , )* Item

By being last-based instead of first-based, it can check for skip-comma with the same test to check for end-of-list. I think this one is very elegant, but I'm not sure about clarity.

Java 8 and later

Using StringJoiner class, and forEach method :

StringJoiner joiner = new StringJoiner(",");
list.forEach(item -> joiner.add(item.toString());
return joiner.toString();

Using Stream, and Collectors:

return list.stream().
map(Object::toString).
collect(Collectors.joining(",")).toString();

Java 7 and earlier

See also #285523

String delim = "";
for (Item i : list) {
sb.append(delim).append(i);
delim = ",";
}

I usually do this :

StringBuffer sb = new StringBuffer();
Iterator it = myList.iterator();
if (it.hasNext()) { sb.append(it.next().toString()); }
while (it.hasNext()) { sb.append(",").append(it.next().toString()); }

Though I think I'll to a this check from now on as per the Java implementation ;)

This is very short, very clear, but gives my sensibilities the creeping horrors. It's also a bit awkward to adapt to different delimiters, especially if a String (not char).

for (Item i : list)
sb.append(',').append(i);
if (sb.charAt(0)==',') sb.deleteCharAt(0);

Inspired by: Last iteration of enhanced for loop in java

If you can use Groovy (which runs on the JVM):

def list = ['a', 'b', 'c', 'd']
println list.join(',')

If you use the Spring Framework you can do it with StringUtils:

public static String arrayToDelimitedString(Object[] arr)
public static String arrayToDelimitedString(Object[] arr, String delim)
public static String collectionToCommaDelimitedString(Collection coll)
public static String collectionToCommaDelimitedString(Collection coll, String delim)

(Copy paste of my own answer from here.) Many of the solutions described here are a bit over the top, IMHO, especially those that rely on external libraries. There is a nice clean, clear idiom for achieving a comma separated list that I have always used. It relies on the conditional (?) operator:

Edit: Original solution correct, but non-optimal according to comments. Trying a second time:

int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
for (int i = 0 ;  i < array.length; i++)
builder.append(i == 0 ? "" : ",").append(array[i]);

There you go, in 4 lines of code including the declaration of the array and the StringBuilder.

2nd Edit: If you are dealing with an Iterator:

    List<Integer> list = Arrays.asList(1, 2, 3);
StringBuilder builder = new StringBuilder();
for (Iterator it = list.iterator(); it.hasNext();)
builder.append(it.next()).append(it.hasNext() ? "," : "");

I didn't compile it... but should work (or be close to working).

public static <T> String toString(final List<T> list,
final String delim)
{
final StringBuilder builder;


builder = new StringBuilder();


for(final T item : list)
{
builder.append(item);
builder.append(delim);
}


// kill the last delim
builder.setLength(builder.length() - delim.length());


return (builder.toString());
}
if (array.length>0)          // edited in response Joachim's comment
sb.append(array[i]);
for (int i=1; i<array.length; i++)
sb.append(",").append(array[i]);

Based on Clearest way to comma-delimit a list (Java)?

Using this idea: Does the last element in a loop deserve a separate treatment?

StringBuffer sb = new StringBuffer();


for (int i = 0; i < myList.size(); i++)
{
if (i > 0)
{
sb.append(", ");
}


sb.append(myList.get(i));
}

I somewhat like this approach, which I found on a blog some time ago. Unfortunately I don't remember the blog's name/URL.

You can create a utility/helper class that looks like this:

private class Delimiter
{
private final String delimiter;
private boolean first = true;


public Delimiter(String delimiter)
{
this.delimiter = delimiter;
}


@Override
public String toString()
{
if (first) {
first = false;
return "";
}


return delimiter;
}
}

Using the helper class is simple as this:

StringBuilder sb = new StringBuilder();
Delimiter delimiter = new Delimiter(", ");


for (String item : list) {
sb.append(delimiter);
sb.append(item);
}
public static String join (List<String> list, String separator) {
String listToString = "";


if (list == null || list.isEmpty()) {
return listToString;
}


for (String element : list) {
listToString += element + separator;
}


listToString = listToString.substring(0, separator.length());


return listToString;
}

One option for the foreach loop is:

StringBuilder sb = new StringBuilder();
for(String s:list){
if (sb.length()>0) sb.append(",");
sb.append(s);
}
Joiner.on(",").join(myList)

Joiner.

public String toString(List<Item> items)
{
StringBuilder sb = new StringBuilder("[");


for (Item item : items)
{
sb.append(item).append(", ");
}


if (sb.length() >= 2)
{
//looks cleaner in C# sb.Length -= 2;
sb.setLength(sb.length() - 2);
}


sb.append("]");


return sb.toString();
}

I like this solution:

String delim = " - ", string = "";


for (String item : myCollection)
string += delim + item;


string = string.substring(delim.length());

I assume it can make use of StringBuilder too.

Because your delimiter is ", " you could use any of the following:

public class StringDelim {


public static void removeBrackets(String string) {
System.out.println(string.substring(1, string.length() - 1));
}


public static void main(String... args) {
// Array.toString() example
String [] arr = {"Hi" , "My", "name", "is", "br3nt"};
String string = Arrays.toString(arr);
removeBrackets(string);


// List#toString() example
List<String> list = new ArrayList<String>();
list.add("Hi");
list.add("My");
list.add("name");
list.add("is");
list.add("br3nt");
string = list.toString();
removeBrackets(string);


// Map#values().toString() example
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("1", "Hi");
map.put("2", "My");
map.put("3", "name");
map.put("4", "is");
map.put("5", "br3nt");
System.out.println(map.values().toString());
removeBrackets(string);


// Enum#toString() example
EnumSet<Days> set = EnumSet.allOf(Days.class);
string = set.toString();
removeBrackets(string);
}


public enum Days {
MON("Monday"),
TUE("Tuesday"),
WED("Wednesday"),
THU("Thursday"),
FRI("Friday"),
SAT("Saturday"),
SUN("Sunday");


private final String day;


Days(String day) {this.day = day;}
public String toString() {return this.day;}
}
}

If your delimiter is ANYTHING else then this isn't going to work for you.

None of the answers uses recursion so far...

public class Main {


public static String toString(List<String> list, char d) {
int n = list.size();
if(n==0) return "";
return n > 1 ? Main.toString(list.subList(0, n - 1), d) + d
+ list.get(n - 1) : list.get(0);
}


public static void main(String[] args) {
List<String> list = Arrays.asList(new String[]{"1","2","3"});
System.out.println(Main.toString(list, ','));
}


}
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");

In my opinion, this is the simplest to read and understand:

StringBuilder sb = new StringBuilder();
for(String string : strings) {
sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();

Java 8 provides several new ways to do this:

Example:

// Util method for strings and other char sequences
List<String> strs = Arrays.asList("1", "2", "3");
String listStr1 = String.join(",", strs);


// For any type using streams and collectors
List<Object> objs = Arrays.asList(1, 2, 3);
String listStr2 = objs.stream()
.map(Object::toString)
.collect(joining(",", "[", "]"));


// Using the new StringJoiner class
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.setEmptyValue("<empty>");
for (Integer i : objs) {
joiner.add(i.toString());
}
String listStr3 = joiner.toString();

The approach using streams assumes import static java.util.stream.Collectors.joining;.

There is a pretty way to achieve this using Java 8:

List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);

Method

String join(List<Object> collection, String delimiter){
StringBuilder stringBuilder = new StringBuilder();
int size = collection.size();
for (Object value : collection) {
size --;
if(size > 0){
stringBuilder.append(value).append(delimiter);
}
}


return stringBuilder.toString();
}

Usage

Given the array of [1,2,3]

join(myArray, ",") // 1,2,3
private String betweenComma(ArrayList<String> strings) {
String united = "";
for (String string : strings) {
united = united + "," + string;
}
return united.replaceFirst(",", "");
}