Оптимизируйте этот метод соединения ArrayList - PullRequest
1 голос
/ 05 марта 2010

Я написал этот код для объединения элементов ArrayList: можно ли его оптимизировать больше?Или есть другой способ лучше?

public static String join(ArrayList list, char delim) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < list.size(); i++) {
            if (i != 0)
                buf.append(delim);
            buf.append((String) list.get(i));
        }
        return buf.toString();
    }

Ответы [ 9 ]

2 голосов
/ 05 марта 2010

Здесь - это то, как это делает известная команда java.util.Collection, поэтому я предполагаю, что это должно быть довольно хорошо;)

  421       /* Returns a string representation of this collection.  The string
  422        * representation consists of a list of the collection's elements in the
  423        * order they are returned by its iterator, enclosed in square brackets
  424        * (<tt>"[]"</tt>).  Adjacent elements are separated by the characters
  425        * <tt>", "</tt> (comma and space).  Elements are converted to strings as
  426        * by {@link String#valueOf(Object)}.
  427        *
  428        * @return a string representation of this collection
  429        */
  430       public String toString() {
  431           Iterator<E> i = iterator();
  432           if (! i.hasNext())
  433               return "[]";
  434   
  435           StringBuilder sb = new StringBuilder();
  436           sb.append('[');
  437           for (;;) {
  438               E e = i.next();
  439               sb.append(e == this ? "(this Collection)" : e);
  440               if (! i.hasNext())
  441                   return sb.append(']').toString();
  442               sb.append(", ");
  443           }

Кроме того, вот как вы получите запятую с ответом Даффимо;)

2 голосов
/ 05 марта 2010

Зачем вам вообще нужен метод?Почему бы просто не использовать метод toString () для List?

public static String join(List<String> list) 
{ 
    return list.toString(); // comma delimiter with some extra stuff at start and end
} 

Вы можете сделать лучше, чем метод, который вы написали.Добавьте интерфейс List и дженерики;может быть, даже коллекция.Это будет более общим и безопасным типом;не требует приведения.

Запустите этот класс:

import java.util.Arrays;
import java.util.List;

public class ListToStringDemo
{
    public static void main(String[] args)
    {
        List<String> values = Arrays.asList(args);
        System.out.println(values);
    }
}

с любыми строковыми аргументами в командной строке (например, "foo bar baz bat") и получите вывод:

C:\JDKs\jdk1.6.0_13\bin\java  ListToStringDemo foo bar baz bat
[foo, bar, baz, bat]

Process finished with exit code 0
2 голосов
/ 05 марта 2010

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

Не вызывайте list.size () каждую итерацию цикла.Либо установите его в качестве переменной, либо используйте Iterator.

Также обратите внимание, что для этого существует множество библиотек, главным образом google collection .Попробуйте следующее:

public String join(List<?> list, char delimiter) {
    StringBuilder result = new StringBuilder();
    for (Iterator<?> i = list.iterator(); i.hasNext();) {
        result.append(i.next());
        if (i.hasNext()) {
            result.append(delimiter);
        }
    }
    return result.toString();
}
1 голос
/ 05 марта 2010

# 1

Вы проверяете размер списка каждый раз, когда цикл повторяется:

for (int i = 0; i < list.size(); i++) {

Поскольку вы не изменяете список, вам нужно сделать это только один раз:

for (int i = 0, j = list.size(); i < j; i++) {

# 2

Вместо проверки i != 0 в каждой итерации, просто добавляйте разделитель после каждой итерации:

    for (int i = 0; i < list.size(); i++) {
        buf.append((String) list.get(i));
        buf.append(delim);
    }

    // Here, convert all but the last character in the buffer to a string.
1 голос
/ 05 марта 2010

Моя первая мысль: Google Collection Joiner класс будет полезным для начала.В частности, метод public final String join(Iterable<?> parts).

1 голос
/ 05 марта 2010

Известно ли, что это наверняка вызывает некоторые проблемы с производительностью, или вы делаете это как упражнение? Если нет, я бы не стал беспокоиться.

Я предположим, это может быть быстрее, но я сомневаюсь в этом:

StringBuffer buf = new StringBuffer();
for (int i = 0; i < list.size() - 1; i++) {
    buf.append((String) list.get(i));
    buf.append(delim);
}
buf.append((String) list.get(i));
return buf.toString();
0 голосов
/ 06 марта 2010

В дополнение к полученным ответам вы можете предварительно инициализировать емкость StringBuilder или StringBuffer. Это сокращает количество повторных копий внутреннего массива при его расширении. Поскольку вы не знаете точную необходимую емкость, вы можете оценить средний размер каждого элемента и умножить его на количество элементов.

private static final int ESTIMATE_ELEM_SIZE = 8;

public static String join(Collection col, char delim)
{
    int len = col.size();
    if (len == 0)
        return "";
    StringBuilder buf = new StringBuilder(ESTIMATE_ELEM_SIZE * len);
    for (Object elem : col)
    {
        buf.append(elem).append(delim);
    }
    return buf.substring(0, buf.length() - 1);
}

Здесь показаны некоторые методы, которыми поделились другие: используйте StringBuilder, не помещайте проверку if в цикл, и используйте расширенный цикл foreach.

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

Обратите внимание, что также нет необходимости приводить к String, поскольку StringBuilder.append() преобразует элемент в String, если это необходимо. Это позволяет использовать это с коллекциями, содержащими другие виды объектов, кроме строк.

0 голосов
/ 05 марта 2010

Я сомневаюсь, что это может быть значительно оптимизировано (имеется в виду, чтобы стать быстрее), не становясь загадочным. Тем не менее, это может быть улучшено с помощью обобщений.

public static String join(List<String> list, char delim) {
   StringBuffer buf = new StringBuffer(512);
   first = true;
   for (String item : list) {
      if (first) {
         first = false;
      } else {
         buf.append(delim);
      }
      buf.append(item);
   }
}

Улучшения в этой версии: вы обеспечиваете, чтобы элемент содержал только строки на уровне компилятора, вам не нужно было поддерживать переменную цикла, и вам не требуется ArrayList, который является подробностью реализации вашего API не должен приводить в исполнение.

0 голосов
/ 05 марта 2010

Лучше, может быть:

Список вместо ArrayList

Программа для интерфейсов без реализаций

для (Строковая строка: строки) вместо для (int i ...)

Циклы foreach от 1.5 на самом деле более эффективны, по словам Джоша, и их гораздо проще поймать

и т. Д., Как и другие отмечали

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...