Лучший способ преобразовать 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
цикл короче и нет необходимости создавать экземпляр a StringBuilder
на каждой итерации.
в 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 выглядит следующим образом, стр2, стр3]
Если у вас есть массив (не 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 разделителя классов возвращает разделитель,за исключением для первого вызова. Таким образом, мы печатаем список без трейлинга (или в данном случае) ведущих сепараторов.
для этого простого случая использования вы можете просто присоединиться к строкам с запятой. Если вы используете 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();
на StringBuilder
будет намного быстрее, чем конкатенация строк, потому что вы не будете повторно создавать экземпляр
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()));
}
}
выход
[Тест И 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 можно использовать печати
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 приведет к тем же накладным расходам, поскольку итератор используется для объекта Iterable (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("\[|\]|,","");