Подтвердить что ты не робот

Самый быстрый способ установить все значения массива?

У меня есть char [], и я хочу установить значение каждого индекса для того же значения char.
Существует очевидный способ сделать это (итерация):

  char f = '+';
  char [] c = new char [50];
  for(int i = 0; i < c.length; i++){
      c[i] = f;
  }

Но мне было интересно, есть ли способ, которым я могу использовать System.arraycopy или что-то подобное, которое обойдется без итерации. Есть ли способ сделать это?

РЕДАКТИРОВАТЬ: От Arrays.java

public static void fill(char[] a, int fromIndex, int toIndex, char val) {
        rangeCheck(a.length, fromIndex, toIndex);
        for (int i = fromIndex; i < toIndex; i++)
            a[i] = val;
    }

Это точно такой же процесс, который показывает, что не может быть лучшего способа сделать это. +1 +1 всем, кто предложил fill в любом случае - вы все правы и благодарны.

4b9b3361

Ответ 2

В качестве еще одного варианта и для потомков я изучал это недавно и нашел эту статью, которая предлагает решение, позволяющее значительно сократить цикл передавая часть работы классу System, который (если JVM, который вы используете, достаточно умен), можно превратить в memset: -

/*
 * initialize a smaller piece of the array and use the System.arraycopy 
 * call to fill in the rest of the array in an expanding binary fashion
 */
public static void bytefill(byte[] array, byte value) {
  int len = array.length;

  if (len > 0){
    array[0] = value;
  }

  for (int i = 1; i < len; i += i) {
    System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i);
  }
}

Это решение было взято из исследовательской статьи IBM "Производительность сервера Java: пример создания эффективных масштабируемых Jvms" Р. Димпси, Р. Арора, К. Койпер.

Упрощенное объяснение

Как следует из комментария, это устанавливает индекс 0 целевого массива в ваше значение, а затем использует класс System для копирования одного объекта т.е. объект с индексом 0 для индекса 1, то эти два объекта (индекс 0 и 1) на 2 и 3, затем эти четыре объекта (0,1,2 и 3) на 4,5,6 и 7 и так далее..

Эффективность (в точке написания)

В быстром прохождении, захват System.nanoTime() до и после и вычисление продолжительности я придумал: -

  • Этот метод: 332,617 - 390,262 ( "самый высокий - самый низкий" из 10 тестов)
  • Float[] n = new Float[array.length]; //Fill with null: 666 650
  • Настройка через петлю: 3,743,488 - 9,767,744 ( "самая высокая - самая низкая" из 10 тестов).
  • Arrays.fill: 12,539,336

Компиляция JVM и JIT

Следует отметить, что по мере развития JVM и JIT этот подход может стать устаревшим, так как оптимизация библиотек и времени выполнения может достигать или даже превышать эти числа, просто используя fill(). На момент написания этой статьи это был самый быстрый вариант, который я нашел. Было упомянуто, что это может быть не сейчас, но я не проверял. Это красота и проклятие Java.

Ответ 3

Используйте Arrays.fill

  char f = '+';
  char [] c = new char [50];
  Arrays.fill(c, f)

Ответ 4

Часто задаваемые вопросы программиста Java Part B В разделе 6 предлагается:

public static void bytefill(byte[] array, byte value) {
    int len = array.length;
    if (len > 0)
    array[0] = value;
    for (int i = 1; i < len; i += i)
        System.arraycopy( array, 0, array, i,
            ((len - i) < i) ? (len - i) : i);
}

Это по сути делает вызовы log2 (array.length) для System.arraycopy, которые, мы надеемся, используют оптимизированную реализацию memcpy.

Однако этот метод все еще требуется для современных JIT Java, таких как Oracle/Android JIT?

Ответ 5

System.arraycopy - мой ответ. Пожалуйста, дайте мне знать, есть ли лучшие способы. спасибо

private static long[] r1 = new long[64];
private static long[][] r2 = new long[64][64];

/**Proved:
 * {@link Arrays#fill(long[], long[])} makes r2 has 64 references to r1 - not the answer;
 * {@link Arrays#fill(long[], long)} sometimes slower than deep 2 looping.<br/>
 */
private static void testFillPerformance() {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    System.out.println(sdf.format(new Date()));
    Arrays.fill(r1, 0l);

    long stamp0 = System.nanoTime();
    //      Arrays.fill(r2, 0l); -- exception
    long stamp1 = System.nanoTime();
    //      System.out.println(String.format("Arrays.fill takes %s nano-seconds.", stamp1 - stamp0));

    stamp0 = System.nanoTime();
    for (int i = 0; i < 64; i++) {
        for (int j = 0; j < 64; j++)
            r2[i][j] = 0l;
    }
    stamp1 = System.nanoTime();
    System.out.println(String.format("Arrays' 2-looping takes %s nano-seconds.", stamp1 - stamp0));

    stamp0 = System.nanoTime();
    for (int i = 0; i < 64; i++) {
        System.arraycopy(r1, 0, r2[i], 0, 64);
    }
    stamp1 = System.nanoTime();
    System.out.println(String.format("System.arraycopy looping takes %s nano-seconds.", stamp1 - stamp0));

    stamp0 = System.nanoTime();
    Arrays.fill(r2, r1);
    stamp1 = System.nanoTime();
    System.out.println(String.format("One round Arrays.fill takes %s nano-seconds.", stamp1 - stamp0));

    stamp0 = System.nanoTime();
    for (int i = 0; i < 64; i++)
        Arrays.fill(r2[i], 0l);
    stamp1 = System.nanoTime();
    System.out.println(String.format("Two rounds Arrays.fill takes %s nano-seconds.", stamp1 - stamp0));
}

12:33:18
2-цикл цикла массивов занимает 133536 наносекунд.
Цикл System.arraycopy занимает 22070 наносекунд.
Один раунд Arrays.fill занимает 9777 наносекунд.
Два раунда Arrays.fill занимает 93028 наносекунд.

12:33:38
2-цикл цикла массивов занимает 133816 наносекунд.
Цикл System.arraycopy занимает 22070 наносекунд.
Один раунд Arrays.fill занимает 17042 наносекунды.
Два раунда Arrays.fill занимает 95263 наносекунды.

12:33:51
2-цикл цикла массивов занимает 199187 наносекунд.
Цикл System.arraycopy занимает 44140 наносекунд.
Один раунд Arrays.fill занимает 19555 наносекунд.
Два раунда Arrays.fill занимает 449219 нано-секунд.

12:34:16
2-цикл цикла массивов занимает 199467 нано-секунд.
Цикл System.arraycopy занимает 42464 наносекунды.
Один раунд Arrays.fill занимает 17600 наносекунд.
Два раунда Arrays.fill занимает 170971 наносекунды.

12:34:26
2-цикл цикла массивов занимает 198907 наносекунд.
Цикл System.arraycopy занимает 24584 наносекунды.
Один раунд Arrays.fill занимает 10616 нано-секунд.
Два раунда Arrays.fill занимает 94426 наносекунд.

Ответ 6

Если у вас есть другой массив из char, char[] b и вы хотите заменить c на b, вы можете использовать c=b.clone();.

Ответ 7

Смотрите метод Arrays.fill:

char f = '+';
char [] c = new char [50];
Arrays.fill(c, f);

Ответ 8

Arrays.fill может удовлетворить ваши потребности

Ответ 9

Arrays.fill(myArray, 'c');

Arrays.fill

Хотя вполне возможно, что это делает цикл в фоновом режиме и поэтому не является более эффективным, чем то, что у вас есть (кроме строк экономии кода). Если вы действительно заботитесь об эффективности, попробуйте следующее по сравнению с приведенным выше:

int size = 50;
char[] array = new char[size];
for (int i=0; i<size; i++){
  array[i] = 'c';
}

Обратите внимание, что указанное выше не вызывает array.size() для каждой итерации.

Ответ 10

   /**
     * Assigns the specified char value to each element of the specified array
     * of chars.
     *
     * @param a the array to be filled
     * @param val the value to be stored in all elements of the array
     */
    public static void fill(char[] a, char val) {
        for (int i = 0, len = a.length; i < len; i++)
            a[i] = val;
    }

То, как это делает Arrays.fill.

(я полагаю, вы могли бы попасть в JNI и использовать memset.)

Ответ 11

Вы можете использовать arraycopy, но это зависит от того, можете ли вы предопределить исходный массив, - нужно ли вам каждый раз заполнять символы, или вы повторно заполняете массивы с помощью того же char?

Ясно, что длина вопросов заполнения - вам нужен источник, который больше, чем все возможные назначения, или вам нужен цикл, чтобы повторно массировать фрагмент данных до тех пор, пока пункт назначения не будет заполнен.

    char f = '+';
    char[] c = new char[50];
    for (int i = 0; i < c.length; i++)
    {
        c[i] = f;
    }

    char[] d = new char[50];
    System.arraycopy(c, 0, d, 0, d.length);

Ответ 12

Arrays.fill - лучший вариант для общего использования. Если вам нужно заполнить большие массивы, хотя на последнем idk 1.8 u102 существует более быстрый способ использования System.arraycopy. Вы можете взглянуть на эту альтернативную Arrays.fill реализацию:

В соответствии с JMH benchmarks вы можете получить почти 2x повышение производительности для больших массивов (1000 +)

В любом случае эти реализации должны использоваться только там, где это необходимо. JDKs Arrays.fill должен быть предпочтительным выбором.