У меня есть ArrayList
, который я хочу вывести полностью как String. По сути, я хочу вывести его в порядке, используя toString
каждого элемента, разделенного вкладками. Есть ли быстрый способ сделать это? Вы можете пропустить его (или удалить каждый элемент) и объединить его в String, но я думаю, что это будет очень медленно.
Лучший способ конвертировать ArrayList в строку
Ответ 1
В принципе, использование цикла для итерации по ArrayList
является единственным вариантом:
НЕ используйте этот код, продолжайте читать в нижней части этого ответа, чтобы понять, почему это нежелательно, и какой код следует использовать вместо этого:
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);
На самом деле конкатенация строк будет прекрасной, так как компилятор javac
оптимизирует конкатенацию строк как последовательность операций append
на StringBuilder
. Здесь часть разборки байт-кода из цикла for
из вышеуказанной программы:
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;
Как видно, компилятор оптимизирует этот цикл с помощью StringBuilder
, поэтому производительность не должна быть большой проблемой.
(ОК, с первого взгляда, экземпляр StringBuilder
создается на каждой итерации цикла, поэтому он может быть не самым эффективным байт-кодом. Создание и использование явного StringBuilder
, вероятно, даст лучшую производительность.)
На самом деле, я думаю, что любой вывод (будь то на диск или на экран) будет по крайней мере на порядок медленнее, чем беспокоиться о производительности конкатенаций строк.
Изменить: Как указано в комментариях, приведенная выше оптимизация компилятора действительно создает новый экземпляр StringBuilder
на каждой итерации. (О чем я уже говорил ранее.)
Самый оптимизированный метод использования будет ответом Paul Tomblin, так как он создает только один объект StringBuilder
вне цикла for
.
Переписывая приведенный выше код, выполните следующие действия:
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());
Будет только экземпляр StringBuilder
один раз за пределами цикла и только сделать два вызова метода append
внутри цикла, о чем свидетельствует этот байт-код (который показывает создание StringBuilder
и цикл)
// 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
Итак, действительно, оптимизация рук должна быть лучше, поскольку внутри цикла for
короче и нет необходимости создавать экземпляр StringBuilder
на каждой итерации.
Ответ 2
В Java 8 или новее:
String listString = String.join(", ", list);
Если list
не относится к типу String, может использоваться соединительный коллектор:
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
Ответ 3
Если вы делаете это на Android, есть хорошая утилита для этого TextUtils, которая имеет метод .join(String delimiter, Iterable)
.
List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);
Очевидно, что не много использования вне Android, но я решил добавить его в эту тему...
Ответ 4
Скачайте Apache Commons Lang и используйте метод
StringUtils.join(list)
StringUtils.join(list, ", ") // 2nd param is the separator.
Конечно, вы можете реализовать это самостоятельно, но их код полностью протестирован и, вероятно, является наилучшей из возможных реализаций.
Я большой поклонник библиотеки Apache Commons и считаю ее отличным дополнением к стандартной библиотеке Java.
Ответ 5
Это довольно старый вопрос, но я полагаю, что я мог бы добавить более современный ответ - используйте класс Joiner
из Guava:
String joined = Joiner.on("\t").join(list);
Ответ 6
Изменение списка на читаемый и значимый String - это действительно общий вопрос, с которым каждый может столкнуться.
Случай 1. Если у вас есть apache StringUtils в вашем пути к классу (как из rogerdpack и Ravi Wallau):
import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);
Случай 2. Если вы только хотите использовать способы из JDK (7):
import java.util.Arrays;
String str = Arrays.toString(myList.toArray());
Просто никогда не создавайте колеса самостоятельно, не используйте цикл для этой однострочной задачи.
Ответ 7
Если бы вы искали быстрый однострочный, с Java 5 вы можете сделать это:
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Кроме того, если ваша цель - просто распечатать содержимое и меньше беспокоиться о "\ t", вы можете просто сделать это:
myList.toString()
который возвращает строку типа
[str1, str2, str3]
Если у вас есть Array (не ArrayList), вы можете сделать то же самое:
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Ответ 8
Прокрутите его и вызовите toString. Существует не волшебный способ, и если бы это было так, как вы думаете, что он будет делать под обложками, кроме того, что он зацикливается? О единственной микро-оптимизации будет использовать StringBuilder вместо String, и даже это не огромная победа. Конкатенация строк превращается в StringBuilder под обложки, но, по крайней мере, если вы напишете ее таким образом, вы сможете увидеть, что происходит.
StringBuilder out = new StringBuilder();
for (Object o : list)
{
out.append(o.toString());
out.append("\t");
}
return out.toString();
Ответ 9
Большинство проектов Java часто имеют доступ к apache-commons lang. Методы StringUtils.join() очень приятны и имеют несколько вкусов для удовлетворения практически каждой потребности.
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();
}
Параметры:
коллекция - коллекция значений для объединения вместе может быть нулевой
разделитель - символ разделителя для использования
Возвращает: объединенная строка, null, если нулевой вход итератора
С: 2.3
Ответ 10
Android имеет класс TextUtil, который вы можете использовать http://developer.android.com/reference/android/text/TextUtils.html
String implode = TextUtils.join("\t", list);
Ответ 11
Элегантный способ справиться с конечными разделительными символами - использовать Сепаратор классов
StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();
Метод toString класса Separator возвращает разделитель, за исключением первого вызова. Таким образом, мы печатаем список без конечных (или в данном случае) ведущих разделителей.
Ответ 12
Для этого простого варианта использования вы можете просто присоединить строки с запятой. Если вы используете Java 8:
String csv = String.join("\t", yourArray);
иначе commons-lang имеет метод join():
String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");
Ответ 13
Класс ArrayList
(Java Docs) расширяет класс AbstractList
, который расширяет класс AbstractCollection
который содержит метод toString()
(Java Docs). Поэтому вы просто пишете
listName.toString();
Разработчики Java уже определили наиболее эффективный способ и дали вам это в хорошо упакованном и документированном методе. Просто позвоните этому методу.
Ответ 14
Это алгоритм O(n)
в любом случае (если вы не сделали многопоточное решение, в котором вы разбили список на несколько подписок, но я не думаю, что это то, о чем вы просите).
Просто используйте StringBuilder
, как показано ниже:
StringBuilder sb = new StringBuilder();
for (Object obj : list) {
sb.append(obj.toString());
sb.append("\t");
}
String finalString = sb.toString();
StringBuilder
будет намного быстрее, чем конкатенация строк, потому что вы не будете повторно создавать объект String
для каждой конкатенации.
Ответ 15
Arrays.toString (current_array)
Ответ 16
В случае, если вы оказались на Android, и вы еще не используете Jack (например, потому что он по-прежнему не имеет поддержки для Instant Run), и если вы хотите больше контролировать форматирование результирующей строки (например, вы хотели бы использовать символ новой строки как разделитель элементов), и использовать/хотите использовать библиотеку StreamSupport (для использования потоков на Java 7 или более ранних версиях компилятора), вы можете использовать что-то вроде этого (я поместил этот метод в свой класс ListUtils ):
public static <T> String asString(List<T> list) {
return StreamSupport.stream(list)
.map(Object::toString)
.collect(Collectors.joining("\n"));
}
И, конечно же, обязательно выполняйте toString() в классе объектов списка.
Ответ 17
Если вам не нужен последний \t после последнего элемента, вам нужно использовать индекс для проверки, но помните, что это только "работает" (то есть O (n)), когда списки реализуют 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());
Ответ 18
Если вы используете Eclipse Collections, вы можете использовать метод makeString()
.
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"));
Если вы можете преобразовать ArrayList
в FastList
, вы можете избавиться от адаптера.
Assert.assertEquals(
"one\ttwo\tthree",
FastList.newListWith("one", "two", "three").makeString("\t"));
Примечание. Я являюсь коммиттером для коллекций Eclipse.
Ответ 19
Ниже приведенный код может помочь вам,
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);
Вывод:
Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3
Ответ 20
Не лучший способ, но элегантный способ.
Arrays.deepToString(Arrays.asList( "Тест", "Тест2" )
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
}
}
Выход
[Test, Test2]
Ответ 21
В Java 8 все просто. Смотрите пример для списка целых чисел:
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)
.reduce((t, u) -> t + "\t" + u)
.orElse("");
Обновление - более короткая версия
String result = Arrays.asList(1,2,3).stream()
.map(Object::toString)
.collect(Collectors.joining("\t"));
Ответ 22
Было бы хорошо:
List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));
Ответ 23
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()
Вы переходите к последовательности new StringJoiner
char, которую вы хотите использовать в качестве разделителя. Если вы хотите сделать CSV: new StringJoiner(", ");
Ответ 24
Если каждый элемент имеет нетривиальное строковое представление, и вы хотите вставить вкладки, единственный способ сделать это - путем циклического цикла.
Ответ 25
Для разделения с помощью вкладок вместо использования println вы можете использовать печать
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");
}
Ответ 26
Почему бы не использовать TextUtils.join? http://developer.android.com/reference/android/text/TextUtils.html
Ответ 27
Я вижу немало примеров, которые зависят от дополнительных ресурсов, но похоже, что это было бы самым простым решением: (именно это я использовал в своем собственном проекте), который в основном просто преобразуется из массива ArrayList в массив, а затем в список.
List<Account> accounts = new ArrayList<>();
public String accountList()
{
Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
String listingString = Arrays.toString(listingArray);
return listingString;
}
Ответ 28
Это уже довольно старый разговор, и теперь apache commons теперь использует StringBuilder внутри: http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line.3045
Это, как мы знаем, повышает производительность, но если производительность имеет решающее значение, используемый метод может быть несколько неэффективным. В то время как интерфейс является гибким и позволит единообразное поведение разных типов коллекций, он несколько неэффективен для списков, который является типом коллекции в исходном вопросе.
Я основываю это на том, что мы накладываем некоторые накладные расходы, которых избегаем, просто повторяя элементы в традиционном цикле. Вместо этого есть некоторые дополнительные вещи, происходящие за кулисами, проверяющие параллельные модификации, вызовы методов и т.д. Усовершенствованный цикл for, с другой стороны, приводит к одинаковым накладным расходам, поскольку итератор используется для объекта Iterable (Список).
Ответ 29
Для этого можно использовать Regex. Это так же кратким, как и получение
System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));
Ответ 30
В одной строке: от [12,0,1,78,12] до 12 0 1 78 12
String srt= list.toString().replaceAll("\\[|\\]|,","");