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



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

1533   28  

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.

Это довольно старый вопрос, но я думаю, я мог бы также добавить более современный ответ - используйте Joiner класс гуавы:

String joined = Joiner.on("\t").join(list);

изменение список для читаемого и значимого строка это действительно распространенный вопрос, с которым может столкнуться каждый.

корпус 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

    Ничего не найдено.