The most sophisticated way for creating comma-separated Strings from a Collection/Array/List?

JavaSqlString

Java Problem Overview


During my work with databases I noticed that I write query strings and in this strings I have to put several restrictions in the where-clause from a list/array/collection. Should look like this:

select * from customer 
where customer.id in (34, 26, ..., 2);

You can simplify this by reducing this to the question that you have collection of strings and want to create a comma-separated list of this strings in just one string.

My approach I have used so far is something like that:

String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
	if(first) {
		result+=string;
		first=false;
	} else {
		result+=","+string;
	}
}

But this is as you can see very ugly. You cannot see what happens there on the first look, especially when the constructed strings (like every SQL query) is getting complicated.

What is your (more) elegant way?

Java Solutions


Solution 1 - Java

Use the http://code.google.com/p/guava-libraries/">Google Guava API's join method:

Joiner.on(",").join(collectionOfStrings);

Solution 2 - Java

Note: This answers was good when it was written 11 years ago, but now there are far better options to do this more cleanly in a single line, both using only Java built-in classes or using a utility library. See other answers below.


Since strings are immutable, you may want to use the StringBuilder class if you're going to alter the String in the code.

The StringBuilder class can be seen as a mutable String object which allocates more memory when its content is altered.

The original suggestion in the question can be written even more clearly and efficiently, by taking care of the redundant trailing comma:

    StringBuilder result = new StringBuilder();
    for(String string : collectionOfStrings) {
        result.append(string);
        result.append(",");
    }
    return result.length() > 0 ? result.substring(0, result.length() - 1): "";

Solution 3 - Java

I just looked at code that did this today. This is a variation on AviewAnew's answer.

collectionOfStrings = /* source string collection */;
String csList = StringUtils.join(collectionOfStrings.toArray(), ",");

The StringUtils ( <-- commons.lang 2.x, or commons.lang 3.x link) we used is from Apache Commons.

Solution 4 - Java

The way I write that loop is:

StringBuilder buff = new StringBuilder();
String sep = "";
for (String str : strs) {
    buff.append(sep);
    buff.append(str);
    sep = ",";
}
return buff.toString();

Don't worry about the performance of sep. An assignment is very fast. Hotspot tends to peel off the first iteration of a loop anyway (as it often has to deal with oddities such as null and mono/bimorphic inlining checks).

If you use it lots (more than once), put it in a shared method.

There is another question on stackoverflow dealing with how to insert a list of ids into an SQL statement.

Solution 5 - Java

Since Java 8, you can use:

Solution 6 - Java

I found the iterator idiom elegant, because it has a test for more elements (ommited null/empty test for brevity):

public static String convert(List<String> list) {
    String res = "";
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        res += iterator.next() + (iterator.hasNext() ? "," : "");
    }
    return res;
}

Solution 7 - Java

There's a lot of manual solutions to this, but I wanted to reiterate and update Julie's answer above. Use google collections Joiner class.

Joiner.on(", ").join(34, 26, ..., 2)

It handles var args, iterables and arrays and properly handles separators of more than one char (unlike gimmel's answer). It will also handle null values in your list if you need it to.

Solution 8 - Java

String.join(", ", collectionOfStrings)

available in the Java8 api.

alternative to (without the need to add a google guava dependency):

Joiner.on(",").join(collectionOfStrings);

Solution 9 - Java

Here's an incredibly generic version that I've built from a combination of the previous suggestions:

public static <T> String buildCommaSeparatedString(Collection<T> values) {
	if (values==null || values.isEmpty()) return "";
	StringBuilder result = new StringBuilder();
	for (T val : values) {
		result.append(val);
		result.append(",");
	}
	return result.substring(0, result.length() - 1);
}

Solution 10 - Java

You could try

List collections = Arrays.asList(34, 26, "...", 2);
String asString = collection.toString();
// justValues = "34, 26, ..., 2"
String justValues = asString.substring(1, asString.length()-1);

Solution 11 - Java

I think it's not a good idea contruct the sql concatenating the where clause values like you are doing :

SELECT.... FROM.... WHERE ID IN( value1, value2,....valueN)

Where valueX comes from a list of Strings.

First, if you are comparing Strings they must be quoted, an this it isn't trivial if the Strings could have a quote inside.

Second, if the values comes from the user,or other system, then a SQL injection attack is possible.

It's a lot more verbose but what you should do is create a String like this:

SELECT.... FROM.... WHERE ID IN( ?, ?,....?)

and then bind the variables with Statement.setString(nParameter,parameterValue).

Solution 12 - Java

This will be the shortest solution so far, except of using Guava or Apache Commons

String res = "";
for (String i : values) {
	res += res.isEmpty() ? i : ","+i;
}

Good with 0,1 and n element list. But you'll need to check for null list. I use this in GWT, so I'm good without StringBuilder there. And for short lists with just couple of elements its ok too elsewhere ;)

Solution 13 - Java

In case someone stumbled over this in more recent times, I have added a simple variation using Java 8 reduce(). It also includes some of the already mentioned solutions by others:

import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringUtils;    

import com.google.common.base.Joiner;

public class Dummy {
  public static void main(String[] args) {

    List<String> strings = Arrays.asList("abc", "de", "fg");
    String commaSeparated = strings
        .stream()
        .reduce((s1, s2) -> {return s1 + "," + s2; })
        .get();
    
    System.out.println(commaSeparated);
    
    System.out.println(Joiner.on(',').join(strings));
    
    System.out.println(StringUtils.join(strings, ","));
    
  }
}

Solution 14 - Java

In Android you should use this:

TextUtils.join(",",collectionOfStrings.toArray());

Solution 15 - Java

Just another method to deal with this problem. Not the most short, but it is efficient and gets the job done.

/**
 * Creates a comma-separated list of values from given collection.
 * 
 * @param <T> Value type.
 * @param values Value collection.
 * @return Comma-separated String of values.
 */
public <T> String toParameterList(Collection<T> values) {
   if (values == null || values.isEmpty()) {
      return ""; // Depending on how you want to deal with this case...
   }
   StringBuilder result = new StringBuilder();
   Iterator<T> i = values.iterator();
   result.append(i.next().toString());
   while (i.hasNext()) {
      result.append(",").append(i.next().toString());
   }
   return result.toString();
}

Solution 16 - Java

There are some third-party Java libraries that provide string join method, but you probably don't want to start using a library just for something simple like that. I would just create a helper method like this, which I think is a bit better than your version, It uses StringBuffer, which will be more efficient if you need to join many strings, and it works on a collection of any type.

public static <T> String join(Collection<T> values)
{
	StringBuffer ret = new StringBuffer();
	for (T value : values)
	{
		if (ret.length() > 0) ret.append(",");
		ret.append(value);
	}
	return ret.toString();
}

Another suggestion with using Collection.toString() is shorter, but that relies on Collection.toString() returning a string in a very specific format, which I would personally not want to rely on.

Solution 17 - Java

If you use Spring, you can do:

StringUtils.arrayToCommaDelimitedString(
    collectionOfStrings.toArray()
)

(package org.springframework.util)

Solution 18 - Java

I'm not sure how "sophisticated" this is, but it's certainly a bit shorter. It will work with various different types of collection e.g. Set<Integer>, List<String>, etc.

public static final String toSqlList(Collection<?> values) {
    		
    String collectionString = values.toString();
    		
    // Convert the square brackets produced by Collection.toString() to round brackets used by SQL
    return "(" + collectionString.substring(1, collectionString.length() - 1) + ")";
}

Exercise for reader: modify this method so that it correctly handles a null/empty collection :)

Solution 19 - Java

What makes the code ugly is the special-handling for the first case. Most of the lines in this small snippet are devoted, not to doing the code's routine job, but to handling that special case. And that's what alternatives like gimel's solve, by moving the special handling outside the loop. There is one special case (well, you could see both start and end as special cases - but only one of them needs to be treated specially), so handling it inside the loop is unnecessarily complicated.

Solution 20 - Java

Join 'methods' are available in Arrays and the classes that extend AbstractCollections but doesn't override toString() method (like virtually all collections in java.util).

For instance:

String s= java.util.Arrays.toString(collectionOfStrings.toArray());
s = s.substing(1, s.length()-1);// [] are guaranteed to be there

That's quite weird way since it works only for numbers alike data SQL wise.

Solution 21 - Java

I've just checked-in a test for my library dollar:

@Test
public void join() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    String string = $(list).join(",");
}

it create a fluent wrapper around lists/arrays/strings/etc using only one static import: $.

NB:

using ranges the previous list can be re-writed as $(1, 5).join(",")

Solution 22 - Java

The nice thing about the IN expression is that if you have repeated values, it does not change the result. So, just duplicate the first item and process the entire list. This assumes that there is at least one item in the list. If there are no items, I'd suggest checking for that first and then not executing the SQL at all.

This will do the trick, is obvious in what it is doing and does not rely on any external libraries:

StringBuffer inString = new StringBuffer(listOfIDs.get(0).toString());
for (Long currentID : listOfIDs) {
  inString.append(",").append(currentID);
}

Solution 23 - Java

While I think your best bet is to use Joiner from Guava, if I were to code it by hand I find this approach more elegant that the 'first' flag or chopping the last comma off.

private String commas(Iterable<String> strings) {
	StringBuilder buffer = new StringBuilder();
	Iterator<String> it = strings.iterator();
	if (it.hasNext()) {
		buffer.append(it.next());
		while (it.hasNext()) {
			buffer.append(',');
			buffer.append(it.next());
		}
	}
	
	return buffer.toString();
}

Solution 24 - Java

if you have an array you can do:

Arrays.asList(parameters).toString()

Solution 25 - Java

Another option, based on what I see here (with slight modifications).

public static String toString(int[] numbers) {
    StringBuilder res = new StringBuilder();
    for (int number : numbers) {
        if (res.length() != 0) {
            res.append(',');
        }
        res.append(number);
    }
    return res.toString();
}

Solution 26 - Java

List<String> collectionOfStrings = // List of string to concat
String csvStrings = StringUtils.collectionToDelimitedString(collectionOfStrings, ",");

StringUtils from springframeowrk:spring-core

Solution 27 - Java

You may be able to use LINQ (to SQL), and you may be able to make use of the Dynamic Query LINQ sample from MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Solution 28 - Java

java.util.List<String> lista = new java.util.ArrayList<String>();
lista.add("Hola");
lista.add("Julio");
System.out.println(lista.toString().replace('[','(').replace(']',')'));

$~(Hola, Julio)

Solution 29 - Java

String commaSeparatedNames = namesList.toString().replaceAll( "[\\[|\\]| ]", "" );  // replace [ or ] or blank

> The string representation consists of a list of the collection's > elements in the order they are returned by its iterator, enclosed in > square brackets ("[]"). Adjacent elements are separated by the > characters ", " (comma and space). > > AbstractCollection javadoc

Solution 30 - Java

List token=new ArrayList(result); final StringBuilder builder = new StringBuilder();

	for (int i =0; i < tokens.size(); i++){
        builder.append(tokens.get(i));
        if(i != tokens.size()-1){
            builder.append(TOKEN_DELIMITER);
        }
    }

builder.toString();

Solution 31 - Java

There is an easy way. You can get your result in a single line.

String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")");

To get complete idea check the code below

 public static void main(String[] args) {       
        List<Integer>memberIds=new ArrayList<Integer>();  //This contain member ids we want to process
        //adding some sample values for example
        memberIds.add(3); 
        memberIds.add(4);
        memberIds.add(2);
        String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")"); //here you will get (3,4,5) That you can directly use in query
        System.out.println(memberIdsModifiedForQuery);
        String exampleQuery="select * from customer where customer.id in "+memberIdsModifiedForQuery+" ";
    }

Solution 32 - Java

The Most easier way in android for convert List to Comma separated String is By useing android.text.TextUtils

 ArrayList<String>Myli = new ArrayList<String>();
 String ArayCommase=android.text.TextUtils.join(",", Myli);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmaerchView Question on Stackoverflow
Solution 1 - JavaJulieView Answer on Stackoverflow
Solution 2 - JavagimelView Answer on Stackoverflow
Solution 3 - JavaOgre Psalm33View Answer on Stackoverflow
Solution 4 - JavaTom Hawtin - tacklineView Answer on Stackoverflow
Solution 5 - JavaAbdullView Answer on Stackoverflow
Solution 6 - JavaMiguel PingView Answer on Stackoverflow
Solution 7 - Javacase nelsonView Answer on Stackoverflow
Solution 8 - JavarobjwilkinsView Answer on Stackoverflow
Solution 9 - JavaJeffView Answer on Stackoverflow
Solution 10 - JavaPeter LawreyView Answer on Stackoverflow
Solution 11 - JavaTelcontarView Answer on Stackoverflow
Solution 12 - JavaiTakeView Answer on Stackoverflow
Solution 13 - JavaChristofView Answer on Stackoverflow
Solution 14 - JavaPascaliusView Answer on Stackoverflow
Solution 15 - JavasilverminkenView Answer on Stackoverflow
Solution 16 - JavaDenis FradlinView Answer on Stackoverflow
Solution 17 - JavaweekensView Answer on Stackoverflow
Solution 18 - JavaDónalView Answer on Stackoverflow
Solution 19 - JavaCarl ManasterView Answer on Stackoverflow
Solution 20 - JavaxssView Answer on Stackoverflow
Solution 21 - JavadfaView Answer on Stackoverflow
Solution 22 - JavaVIMView Answer on Stackoverflow
Solution 23 - JavaVictorView Answer on Stackoverflow
Solution 24 - Javacloudy_weatherView Answer on Stackoverflow
Solution 25 - JavaelcucoView Answer on Stackoverflow
Solution 26 - JavaSridharView Answer on Stackoverflow
Solution 27 - JavaGregUzelacView Answer on Stackoverflow
Solution 28 - JavaJulio CésarView Answer on Stackoverflow
Solution 29 - JavaTodd GattsView Answer on Stackoverflow
Solution 30 - JavaUpsView Answer on Stackoverflow
Solution 31 - JavaFathah Rehman PView Answer on Stackoverflow
Solution 32 - JavaJayman JaniView Answer on Stackoverflow