У меня есть ArrayList
, который я хочу вывести полностью как String. По сути, я хочу вывести его в порядке, используя toString
каждого элемента, разделенного вкладками. Есть ли быстрый способ сделать это? Вы можете пропустить его (или удалить каждый элемент) и объединить его в String, но я думаю, что это будет очень медленно.Лучший способ конвертировать ArrayList в строку
ответ
В принципе, с помощью цикла перебрать 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
короче nd нет необходимости создавать экземпляр StringBuilder
на каждой итерации.
Спасибо за ваш ответ. Я не понял, что компилятор, вероятно, оптимизирует его! –
@Juan Besa: Хотя я слышал об этой оптимизации в прошлом, это был первый раз, когда я действительно пытался проверить, действительно ли это происходит (фактически глядя на байт-код), так что это была возможность обучения для меня :) – coobird
По соображениям производительности рассмотрите возможность использования класса StringBuilder вместо просто добавляемых строк. – Jeremy
Пройдите через него и позвоните в строку. Существует не волшебный способ, и если бы это было так, как вы думаете, что он будет делать под обложками, кроме того, что он зацикливается? О единственной микро-оптимизации будет использовать StringBuilder вместо String, и даже это не огромная победа. Конкатенация строк превращается в StringBuilder под обложки, но, по крайней мере, если вы напишете ее таким образом, вы сможете увидеть, что происходит.
StringBuilder out = new StringBuilder();
for (Object o : list)
{
out.append(o.toString());
out.append("\t");
}
return out.toString();
Спасибо! это то, что я заканчиваю делать :) –
Для больших массивов это, безусловно, не микро-оптимизация. Автоматическое преобразование для использования StringBuilder выполняется отдельно для каждой конкатенации строк, что не помогает в случае цикла. Это нормально, если вы объединяете большое количество элементов в одном выражении. – starblue
Использование StringBuilder явно имеет большое значение, если вы конкатенируете, скажем, 50 000 строк, составляющих ~ 1 Мб строки результата - это может быть разница в 1 минуту по сравнению с 1 с временем выполнения. –
Если каждый элемент имеет нетривиальное строковое представление, и вы хотите вставить вкладки, единственный способ сделать это - это цикл.
Это алгоритм O(n)
в любом случае (если вы не сделали многопоточное решение, в котором вы разбили список на несколько подписок, но я не думаю, что это то, о чем вы просите).
Просто используйте StringBuilder
, как показано ниже:
StringBuilder sb = new StringBuilder();
for (Object obj : list) {
sb.append(obj.toString());
sb.append("\t");
}
String finalString = sb.toString();
StringBuilder
будет намного быстрее, чем конкатенация строки, потому что не будет повторно инстанцирование String
объекта на каждую конкатенации.
Большинство проектов 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
Это очень приятно, так как метод 'join (...)' имеет варианты как для массивов, так и для коллекций. – vikingsteve
Скачать Jakarta Commons Lang и использовать метод
StringUtils.join(list)
Вы можете реализовать его самостоятельно, конечно, но их код полностью протестирован и, вероятно, является наилучшей возможной реализацией.
Я большой поклонник библиотеки Jakarta Commons, и я также думаю, что это отличное дополнение к стандартной библиотеке Java.
Если вам не нужен последний \ 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());
Элегантный способ борьбы с задними символами разделения заключается в использовании Class Separator
StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();
Метод ToString Класс Сепаратор возвращает separater, исключения для первого вызова. Таким образом, мы печатаем список без трейлинговых (или в данном случае) ведущих разделителей.
Это довольно старый разговор сейчас и Apache Commons теперь используют StringBuilder внутри: http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line.3045
Это будет, как мы знаем, повысить производительность, но если производительность критична, то метод может быть несколько неэффективным. В то время как интерфейс является гибким и позволит единообразное поведение разных типов коллекций, он несколько неэффективен для списков, который является типом коллекции в исходном вопросе.
Я основываю это на том, что мы выполняем некоторые накладные расходы, которых мы избегаем, просто повторяя элементы в традиционном цикле. Вместо этого есть некоторые дополнительные вещи, происходящие за кулисами, проверяющие параллельные модификации, вызовы методов и т. Д. С другой стороны, усиленный для цикла результат приводит к одинаковым накладным расходам, поскольку итератор используется для объекта Iterable (Список).
Это довольно старый вопрос, но я полагаю, что я мог бы также добавить более современный ответ - использовать Joiner
класс от Guava:
String joined = Joiner.on("\t").join(list);
Приятно, спасибо. Мне нравится Гуава лучше. –
Это мое любимое решение. : -> +1 для гуавы. – csgeek
Ctrl + F'd для Guava. Благодаря! –
Если вам случится делать это на 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, но полагал, что я хотел бы добавить его к этой теме ...
Как насчет того, содержит ли мой список пользовательский класс? Например, если у меня есть список
Поскольку 'TextUtils.join' принимает' Object [] ', Я бы предположил что он вызывает 'toString()' на каждом токене. Использует ли 'PatientDetails'' toString() '? Если это не решит проблему, вы можете застрять что-то с классом «Separator». –
'public static String join (разделитель CharSequence, Iterable tokens)' Использование raw-типа в новой библиотеке действительно является ошибкой на стороне Google. Особенно, когда его легко можно было бы обобщить на 'public static
Arrays.toString (current_array)
Arrays.toString() ожидает массив. Речь идет о печати списка (массива). См. Комментарий Кена Шиха для улучшения ответа на этот вопрос. – Torsten
Emm .. где проблема? ..))) http://docs.oracle.com/javase/6/docs/api/java/util/List.html#toArray() – Akvel
Да, это также то, что содержится в ответе Кена Ши, как я писал раньше , Я просто указывал, что ваш ответ еще не совсем завершен или не полностью ответил на вопрос об оригинальном плакате. Он не искал способ распечатать массив, но список. Ваш ответ показывает способ печати массива. – Torsten
Почему бы не использовать TextUtils.join? http://developer.android.com/reference/android/text/TextUtils.html
Поскольку TextUtils специфичен для Android. – Reyske
Если вы ищете быстрый однострочника, по состоянию на Java 5 вы можете сделать это:
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Кроме того, если ваша цель просто распечатать содержимое и менее обеспокоены "\ т", вы можете просто сделать это:
myList.toString()
, который возвращает строку, как
[str1, str2, str3 ]
Если у вас есть массив (не ArrayList), то вы можете сделать то же самое, как это:
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
Я думаю, что это на самом деле более эффективно, чем методы, описанные выше. Такой позор показан внизу. Это может быть не изящно, но я твердо верю, что ваше решение работает O (n), в то время как другие теоретически выполняются в O (n^2) (поскольку строки Java неизменяемы, вы в основном создаете новую строку при каждом слиянии, и это становится хуже, поскольку итоговая строка становится больше) – user3790827
Если ваш текст очень большой, вы в конечном итоге едите ресурсы своих компьютеров. – user3790827
Этот метод в 7-8 раз медленнее, чем при использовании StringBuilder. – Zoka
ArrayList
класс (Java Docs) расширяет AbstractList
класс, который расширяет AbstractCollection
класс, содержащий метод toString()
(Java Docs). Таким образом, вы просто написать
listName.toString();
Java разработчики уже выяснили, наиболее эффективный способ и дали вам, что в хорошо упакованный и документированный метод. Просто позвоните этому методу.
Если вы используете 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.
Как насчет этой функции:
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();
}
это работает для любого типа коллекции ...
В Java 8 или более поздней версии:
String listString = String.join(", ", list);
В случае list
не из тип String, может использоваться соединительный коллектор:
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
Я не могу поверить, что потребовалось до тех пор, пока Java 8 не добавит этого. – Paul
Этот ответ должен быть проголосован больше! Нет хаков, нет библиотек и нет циклов. – Songo
это не работает для того, что сказал ОП. String.join принимает второй аргумент Iterable расширяет CharSequence>. Таким образом, он работает, если у вас есть список
Android имеет класс TextUtil вы можете использовать http://developer.android.com/reference/android/text/TextUtils.html
String implode = TextUtils.join("\t", list);
хорошее решение .... – Sreekanth
Дубликат к http: // stackoverflow.com/a/7779427/3679632 –
Это решение лучше, чем String.join, для чего требуется API 26+ –
Код ниже может помочь вам,
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
Для разделяющей с использованием вкладок вместо использования 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");
}
Не может быть лучшим способом, но элегантным способом.
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()));
}
}
Выход
[Тест, Test2]
Я думаю, что это лучший способ, если «лучший» означает читаемость кода. Я не смотрел код, но он, вероятно, так же эффективен, как метод StringBuilder (он, вероятно, использует StringBuilder под капотом), хотя и не так настраивается на выходе. –
Вы можете использовать Regex для этого. Это является настолько кратким, как он получает
System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));
В 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 проще, чем это. – Bartzilla
Это было мое первое впечатление. Но после того, как я привык к этому, я нахожу это замечательным. Например, вы можете добавлять такие операции, как 'filter'. В конце мне намного легче прочитать код. – amra
В Java 8: String.join ("\ t", array) – Tomasz
Изменение Список в читаемый и содержательный Строка действительно общий вопрос, что каждый может столкнуться.
Дело 1.Если у вас есть StringUtils Апача в своем классе пути (как из rogerdpack и Рави Валлау):
import org.apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);
Случай 2. Если вы хотите использовать только пути из JDK (7):
import java.util.Arrays;
String str = Arrays.toString(myList.toArray());
Просто никогда не строить колеса самостоятельно, не использовать петлю для этой одной строки задачи.
Я не заметил ваше решение Case 2, прежде чем публиковать свои собственные. Ваш на самом деле намного лучше и сохраняет дополнительный шаг. Я определенно рекомендую его по некоторым ответам, которые, как представляется, требуют дополнительных инструментов. – Elliander
'Arrays.toString (myList.toArray())' - самое простое и самое простое решение. –
Я вижу немало примеров, которые зависят от дополнительных ресурсов, но похоже, что это было бы самым простым решением (это то, что я использовал в своем собственном проекте), которое в основном просто преобразуется из массива ArrayList в массив и затем в список.
List<Account> accounts = new ArrayList<>();
public String accountList()
{
Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
String listingString = Arrays.toString(listingArray);
return listingString;
}
будет следующим ничего хорошего:
List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));
В случае, если вам случится быть на Android, и вы не используете Джек еще (например, потому что она по-прежнему не хватает поддержки 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() в классе объектов списка.
Использование 'reduce' крайне неэффективно для конкатенации строк. Вы должны сделать это с помощью Java 8-way 'return StreamSupport.stream (list) .map (Object :: toString) .collect (join (" \ n "))', который внутренне использует 'StringJoiner'. Нет причин, по которым вы не могли бы это сделать с помощью [streamsupport] (https://sourceforge.net/projects/streamsupport/). –
Другое дело, что ваш код будет ужасно (из-за 'Optional # get'), если он получит пустой список. –
@StefanZobel Спасибо за то, что вы указали эффективность и проблемы с корпусом. Изменен код. – Metallica
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()
Проходите к new StringJoiner
последовательности обугленных вы хотите использовать в качестве разделителя. Если вы хотите сделать CSV: new StringJoiner(", ");
_или удалить каждый элемент. Будьте осторожны, удаление элементов из списка ArrayList является большим NO-NO, так как ваш «цикл» займет квадратичное время из-за смещения элементов (при условии, что вы зацикливаете от первого до последнего элемента). –
То же самое для коллекций: http://stackoverflow.com/questions/395401/printing-java-collections-nicely-tostring-doesnt-return-pretty-output –