Лучший способ конвертировать ArrayList в строку

У меня есть ArrayList, который я хочу вывести полностью как String. По сути, я хочу вывести его в порядке, используя toString каждого элемента, разделенного вкладками. Есть ли быстрый способ сделать это? Вы можете пропустить его (или удалить каждый элемент) и объединить его в String, но я думаю, что это будет очень медленно.

Ответ 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

Ответ 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");
}

Ответ 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("\\[|\\]|,","");