Лучший способ преобразовать ArrayList в строку
у меня есть ArrayList что я хочу вывести полностью в виде строки. По сути, я хочу вывести его в порядке использования toString каждого элемента, разделенных вкладками. Есть ли быстрый способ сделать это? Вы можете перебрать его (или удалить каждый элемент) и объединить его в строку, но я думаю, что это будет очень медленно.
28 ответов:
в основном, используя цикл для итерации по
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вероятно, даст лучшую производительность.)в самом деле, я думаю, что наличие любого вида вывода (будь то на диск или на экран) будет по крайней мере на порядок медленнее, чем беспокоиться о производительности конкатенаций строк.
Edit: как указано в комментариях, приведенная выше оптимизация компилятора действительно создает новый экземпляр
StringBuilderна каждой итерации. (Что я уже отмечал ранее.)самый оптимизированный метод для использования будет ответом Павел Томблин, так как он только создает экземпляр одного
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цикл короче и нет необходимости создавать экземпляр aStringBuilderна каждой итерации.
в Java 8 или более поздней версии:
String listString = String.join(", ", list);В случае
listне имеет типа String, можно использовать соединительный коллектор:String listString = list.stream().map(Object::toString) .collect(Collectors.joining(", "));
Если вы случайно делаете это на 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, но я решил добавить его в эту тему...
загрузите Jakarta Commons Lang и используйте метод
StringUtils.join(list)вы можете реализовать ее самостоятельно, конечно, но их код полностью протестирован и является лучшей возможной реализации.
Я большой поклонник библиотеки Jakarta Commons, и я также думаю, что это отличное дополнение к стандартной библиотеке Java.
изменение список для читаемого и значимого строка это действительно распространенный вопрос, с которым может столкнуться каждый.
корпус 1. Если у вас есть StringUtils apache в вашем пути к классу (как из 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());просто никогда не стройте колеса самостоятельно, не используйте цикл для этой однострочной задачи.
Если вы искали быстрый однострочный, как Java 5 Вы можете сделать это:
myList.toString().replaceAll("\[|\]", "").replaceAll(", ","\t")кроме того, если ваша цель-просто распечатать содержимое и меньше беспокоиться о "\t", вы можете просто сделать это:
myList.toString()который возвращает строку типа
[str1, str2, str3]
Если у вас есть массив (не ArrayList), то вы можете сделать то же самое, как это:
Arrays.toString(myList).replaceAll("\[|\]", "").replaceAll(", ","\t")
цикл через него и вызов toString. Нет никакого волшебного способа, и если бы он был, как вы думаете, что он делал бы под одеялом, кроме как петля через него? О единственной микро-оптимизации было бы использовать StringBuilder вместо String, и даже это не огромная победа - конкатенация строк превращается в StringBuilder под обложками, но, по крайней мере, если вы пишете это так, вы можете видеть, что происходит.
StringBuilder out = new StringBuilder(); for (Object o : list) { out.append(o.toString()); out.append("\t"); } return out.toString();
большинство проектов 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
разделитель - символ разделителя для использования
возвращает: соединенная строка, null, если нулевой итератор вход
С тех пор: 2.3
Android имеет класс TextUtil, который вы можете использовать http://developer.android.com/reference/android/text/TextUtils.html
String implode = TextUtils.join("\t", list);
элегантный способ справиться с конечными символами разделения-использовать Разделитель Класс
StringBuilder buf = new StringBuilder(); Separator sep = new Separator("\t"); for (String each: list) buf.append(sep).append(each); String s = buf.toString();метод toString класса Separator возвращает разделитель,за исключением для первого вызова. Таким образом, мы печатаем список без замыкающих (или в данном случае) ведущих разделителей.
в этом простом случае использования вы можете просто соединить строки с запятой. Если вы используете Java 8:
String csv = String.join("\t", yourArray);в противном случае commons-lang имеет метод join ():
String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");
Это
O(n)алгоритм в любом случае (если вы не сделали какое-то многопоточное решение, где вы разбили список на несколько подсписков, но я не думаю, что это то, что вы просите).просто использовать
StringBuilderкак показано ниже:StringBuilder sb = new StringBuilder(); for (Object obj : list) { sb.append(obj.toString()); sb.append("\t"); } String finalString = sb.toString();The
StringBuilderбудет намного быстрее, чем конкатенация строк, потому что вы не будете повторно создавать экземпляр a
ArrayListкласса ( Java Docs) расширяетAbstractListкласс, который расширяетAbstractCollectionкласс, который содержитtoString()метод ( Java Docs). Так что вы просто пишитеlistName.toString();разработчики Java уже выяснили наиболее эффективный способ и дали вам это в красиво упакованном и документированном методе. Просто вызовите этот метод.
в случае, если вы оказались на Android и вы не используете Джека (например, потому что он по-прежнему не хватает поддержки для немедленного выполнения), и если вы хотите больше контроля над форматированием получившейся строки (например, вы хотите использовать символ новой строки как разделитель элементов), и используете/хотите использовать StreamSupport библиотеки (для использования потоков в Java 7 или более ранней версии компилятора), вы могли бы использовать что-то вроде этого (я положил этот метод в моем ListUtils класс):
public static <T> String asString(List<T> list) { return StreamSupport.stream(list) .map(Object::toString) .collect(Collectors.joining("\n")); }и, конечно же, не забудьте реализовать toString() в классе объектов вашего списка.
может быть не лучший способ, но элегантный способ.
массивы.deepToString (массивы.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())); } }выход
[Test, Test2]
если вы используете Коллекции Eclipse можно использовать
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.
List<String> stringList = getMyListOfStrings(); StringJoiner sj = new StringJoiner(" "); stringList.stream().forEach(e -> sj.add(e)); String spaceSeparated = sj.toString()передать в
new StringJoinerпоследовательность символов, которую вы хотите использовать в качестве разделителя. Если вы хотите сделать CSV:new StringJoiner(", ");
ниже код может помочь вам,
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
в 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("");
было бы хорошо следующее:
List<String> streamValues = new ArrayList<>(); Arrays.deepToString(streamValues.toArray()));
Если вы не хотите последний \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());
для разделения с помощью вкладок вместо использования println можно использовать 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"); }
Я вижу довольно много примеров, которые зависят от дополнительных ресурсов, но, похоже, это было бы самым простым решением: (что я использовал в своем собственном проекте), который в основном просто преобразуется из ArrayList в массив, а затем в список.
List<Account> accounts = new ArrayList<>(); public String accountList() { Account[] listingArray = accounts.toArray(new Account[accounts.size()]); String listingString = Arrays.toString(listingArray); return listingString; }
Это уже довольно старый разговор, и apache commons теперь использует StringBuilder внутри: http://commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line.3045
Это, как мы знаем, улучшит производительность, но если производительность критична, то используемый метод может быть несколько неэффективным. В то время как интерфейс является гибким и позволит обеспечить согласованное поведение между различными типами коллекций это несколько неэффективно для списков, которые являются типом коллекции в исходном вопросе.
я основываю это на том, что мы несем некоторые накладные расходы, которые мы могли бы избежать, просто повторяя элементы в традиционном цикле for. Вместо этого есть некоторые дополнительные вещи, происходящие за кулисами, проверяющие параллельные модификации, вызовы методов и т. д. С другой стороны, расширенный цикл for приведет к тем же накладным расходам, поскольку итератор используется для итеративного объекта (the Список.)
для этого можно использовать регулярное выражение. Это так кратко, как он получает
System.out.println(yourArrayList.toString().replaceAll("\[|\]|[,][ ]","\t"));
Как насчет этой функции:
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(); }это работает для любого типа коллекции...
в одной строке : От [12,0,1,78,12] до 12 0 1 78 12
String srt= list.toString().replaceAll("\[|\]|,","");
Comments