Reputation: 4410
I have an ArrayList
that I want to output completely as a String. Essentially I want to output it in order using the toString
of each element separated by tabs. Is there any fast way to do this? You could loop through it (or remove each element) and concatenate it to a String but I think this will be very slow.
Upvotes: 352
Views: 1591514
Reputation: 4170
Android has a TextUtil
class you can use:
String implode = TextUtils.join("\t", list);
Upvotes: 17
Reputation: 161022
Java 8 introduces a String.join(separator, list)
method; see Vitalii Federenko's answer.
Before Java 8, using a loop to iterate over the ArrayList
was the only option:
DO NOT use this code, continue reading to the bottom of this answer to see why it is not desirable, and which code should be used instead:
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
String listString = "";
for (String s : list)
{
listString += s + "\t";
}
System.out.println(listString);
In fact, a string concatenation is going to be just fine, as the javac
compiler will optimize the string concatenation as a series of append
operations on a StringBuilder
anyway. Here's a part of the disassembly of the bytecode from the for
loop from the above program:
61: new #13; //class java/lang/StringBuilder
64: dup
65: invokespecial #14; //Method java/lang/StringBuilder."<init>":()V
68: aload_2
69: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: aload 4
74: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
77: ldc #16; //String \t
79: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
82: invokevirtual #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
As can be seen, the compiler optimizes that loop by using a StringBuilder
, so performance shouldn't be a big concern.
(OK, on second glance, the StringBuilder
is being instantiated on each iteration of the loop, so it may not be the most efficient bytecode. Instantiating and using an explicit StringBuilder
would probably yield better performance.)
In fact, I think that having any sort of output (be it to disk or to the screen) will be at least an order of a magnitude slower than having to worry about the performance of string concatenations.
Edit: As pointed out in the comments, the above compiler optimization is indeed creating a new instance of StringBuilder
on each iteration. (Which I have noted previously.)
The most optimized technique to use will be the response by Paul Tomblin, as it only instantiates a single StringBuilder
object outside of the for
loop.
Rewriting to the above code to:
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder();
for (String s : list)
{
sb.append(s);
sb.append("\t");
}
System.out.println(sb.toString());
Will only instantiate the StringBuilder
once outside of the loop, and only make the two calls to the append
method inside the loop, as evidenced in this bytecode (which shows the instantiation of StringBuilder
and the loop):
// Instantiation of the StringBuilder outside loop:
33: new #8; //class java/lang/StringBuilder
36: dup
37: invokespecial #9; //Method java/lang/StringBuilder."<init>":()V
40: astore_2
// [snip a few lines for initializing the loop]
// Loading the StringBuilder inside the loop, then append:
66: aload_2
67: aload 4
69: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: pop
73: aload_2
74: ldc #15; //String \t
76: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
79: pop
So, indeed the hand optimization should be better performing, as the inside of the for
loop is shorter and there is no need to instantiate a StringBuilder
on each iteration.
Upvotes: 389
Reputation: 16935
In Java 8 it's simple. See example for list of integers:
String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "\t" + u).orElse("");
Or multiline version (which is simpler to read):
String result = Arrays.asList(1,2,3).stream()
.map(Object::toString)
.reduce((t, u) -> t + "\t" + u)
.orElse("");
String result = Arrays.asList(1,2,3).stream()
.map(Object::toString)
.collect(Collectors.joining("\t"));
Upvotes: 18
Reputation: 10493
Download the Apache Commons Lang and use the method
StringUtils.join(list)
StringUtils.join(list, ", ") // 2nd param is the separator.
You can implement it by yourself, of course, but their code is fully tested and is probably the best possible implementation.
I am a big fan of the Apache Commons library and I also think it's a great addition to the Java Standard Library.
Upvotes: 258
Reputation: 811
For seperating using tabs instead of using println you can use print
ArrayList<String> mylist = new ArrayList<String>();
mylist.add("C Programming");
mylist.add("Java");
mylist.add("C++");
mylist.add("Perl");
mylist.add("Python");
for (String each : mylist)
{
System.out.print(each);
System.out.print("\t");
}
Upvotes: 2
Reputation: 554
In one Line : From [12,0,1,78,12] to 12 0 1 78 12
String srt= list.toString().replaceAll("\\[|\\]|,","");
Upvotes: 5
Reputation: 6351
For this simple use case, you can simply join the strings with comma. If you use Java 8:
String csv = String.join("\t", yourArray);
otherwise commons-lang has a join() method:
String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");
Upvotes: 19
Reputation: 27813
An elegant way to deal with trailing separation characters is to use Class Separator
StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();
The toString method of Class Separator returns the separater, except for the first call. Thus we print the list without trailing (or in this case) leading separators.
Upvotes: 13
Reputation: 37177
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()
You pass to the new StringJoiner
the char sequence you want to be used as separator. If you want to do a CSV: new StringJoiner(", ");
Upvotes: 4
Reputation: 1503290
This is a pretty old question, but I figure I might as well add a more modern answer - use the Joiner
class from Guava:
String joined = Joiner.on("\t").join(list);
Upvotes: 142
Reputation: 6026
In case you happen to be on Android and you are not using Jack yet (e.g. because it's still lacking support for Instant Run), and if you want more control over formatting of the resulting string (e.g. you would like to use the newline character as the divider of elements), and happen to use/want to use the StreamSupport library (for using streams on Java 7 or earlier versions of the compiler), you could use something like this (I put this method in my ListUtils class):
public static <T> String asString(List<T> list) {
return StreamSupport.stream(list)
.map(Object::toString)
.collect(Collectors.joining("\n"));
}
And of course, make sure to implement toString() on your list objects' class.
Upvotes: 6
Reputation: 26748
If you're using Eclipse Collections, you can use the makeString()
method.
ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Assert.assertEquals(
"one\ttwo\tthree",
ArrayListAdapter.adapt(list).makeString("\t"));
If you can convert your ArrayList
to a FastList
, you can get rid of the adapter.
Assert.assertEquals(
"one\ttwo\tthree",
FastList.newListWith("one", "two", "three").makeString("\t"));
Note: I am a committer for Eclipse Collections.
Upvotes: 3
Reputation: 2228
Changing List to a readable and meaningful String is really a common question that every one may encounter.
Case 1. If you have apache's StringUtils in your class path (as from rogerdpack and Ravi Wallau):
import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);
Case 2 . If you only want to use ways from JDK(7):
import java.util.Arrays;
String str = Arrays.toString(myList.toArray());
Just never build wheels by yourself, dont use loop for this one-line task.
Upvotes: 94
Reputation: 1108
Would the following be any good:
List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));
Upvotes: 3
Reputation: 511
I see quite a few examples which depend on additional resources, but it seems like this would be the simplest solution: (which is what I used in my own project) which is basically just converting from an ArrayList to an Array and then to a List.
List<Account> accounts = new ArrayList<>();
public String accountList()
{
Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
String listingString = Arrays.toString(listingArray);
return listingString;
}
Upvotes: 1
Reputation: 654
You can use a Regex for this. This is as concise as it gets
System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));
Upvotes: 0
Reputation: 2149
May not be the best way, but elegant way.
Arrays.deepToString(Arrays.asList("Test", "Test2")
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
}
}
Output
[Test, Test2]
Upvotes: 3
Reputation: 114550
In Java 8 or later:
String listString = String.join(", ", list);
In case the list
is not of type String, a joining collector can be used:
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
Upvotes: 1235
Reputation: 3143
The below code may help you,
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
String str = list.toString();
System.out.println("Step-1 : " + str);
str = str.replaceAll("[\\[\\]]", "");
System.out.println("Step-2 : " + str);
Output:
Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3
Upvotes: 3
Reputation: 733
If you were looking for a quick one-liner, as of Java 5 you can do this:
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Additionally, if your purpose is just to print out the contents and are less concerned about the "\t", you can simply do this:
myList.toString()
which returns a string like
[str1, str2, str3]
If you have an Array (not ArrayList) then you can accomplish the same like this:
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Upvotes: 66
Reputation: 116040
How about this function:
public static String toString(final Collection<?> collection) {
final StringBuilder sb = new StringBuilder("{");
boolean isFirst = true;
for (final Object object : collection) {
if (!isFirst)
sb.append(',');
else
isFirst = false;
sb.append(object);
}
sb.append('}');
return sb.toString();
}
it works for any type of collection...
Upvotes: -1
Reputation: 1065
It's an O(n)
algorithm either way (unless you did some multi-threaded solution where you broke the list into multiple sublists, but I don't think that is what you are asking for).
Just use a StringBuilder
as below:
StringBuilder sb = new StringBuilder();
for (Object obj : list) {
sb.append(obj.toString());
sb.append("\t");
}
String finalString = sb.toString();
The StringBuilder
will be a lot faster than string concatenation because you won't be re-instantiating a String
object on each concatenation.
Upvotes: 6
Reputation: 10579
If you happen to be doing this on Android, there is a nice utility for this called TextUtils which has a .join(String delimiter, Iterable)
method.
List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);
Obviously not much use outside of Android, but figured I'd add it to this thread...
Upvotes: 426
Reputation: 182850
Loop through it and call toString. There isn't a magic way, and if there were, what do you think it would be doing under the covers other than looping through it? About the only micro-optimization would be to use StringBuilder instead of String, and even that isn't a huge win - concatenating strings turns into StringBuilder under the covers, but at least if you write it that way you can see what's going on.
StringBuilder out = new StringBuilder();
for (Object o : list)
{
out.append(o.toString());
out.append("\t");
}
return out.toString();
Upvotes: 38
Reputation: 161
This is quite an old conversation by now and apache commons are now using a StringBuilder internally: http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line.3045
This will as we know improve performance, but if performance is critical then the method used might be somewhat inefficient. Whereas the interface is flexible and will allow for consistent behaviour across different Collection types it is somewhat inefficient for Lists, which is the type of Collection in the original question.
I base this in that we are incurring some overhead which we would avoid by simply iterating through the elements in a traditional for loop. Instead there are some additional things happening behind the scenes checking for concurrent modifications, method calls etc. The enhanced for loop will on the other hand result in the same overhead since the iterator is used on the Iterable object (the List).
Upvotes: 0
Reputation:
If you don't want the last \t after the last element, you have to use the index to check, but remember that this only "works" (i.e. is O(n)) when lists implements the RandomAccess.
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
StringBuilder sb = new StringBuilder(list.size() * apprAvg); // every apprAvg > 1 is better than none
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
if (i < list.size() - 1) {
sb.append("\t");
}
}
System.out.println(sb.toString());
Upvotes: 4
Reputation: 13571
Most Java projects often have apache-commons lang available. StringUtils.join() methods is very nice and has several flavors to meet almost every need.
public static java.lang.String join(java.util.Collection collection,
char separator)
public static String join(Iterator iterator, String separator) {
// handle null, zero and one elements before building a buffer
Object first = iterator.next();
if (!iterator.hasNext()) {
return ObjectUtils.toString(first);
}
// two or more elements
StringBuffer buf =
new StringBuffer(256); // Java default is 16, probably too small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
if (separator != null) {
buf.append(separator);
}
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
Parameters:
collection - the Collection of values to join together, may be null
separator - the separator character to use
Returns: the joined String, null if null iterator input
Since: 2.3
Upvotes: 37