Манипулирование массивами в отношении диапазона значений

#java #arrays

#java #массивы

Вопрос:

У меня есть такое требование, что мне нужно установить значения в байтовом массиве размером 20 МБ.

Я ищу JAVA API, который выполняет следующее. Я просмотрел apache commons arrayutils, но не смог найти что-то полезное.

Операция должна быть примерно такого типа. Допустим, значения варьируются от 0 до 100.

Я хотел бы манипулировать массивом таким образом, чтобы значения меньше 15 менялись на 15, а значения больше 70 менялись на 70.

По сути, я ищу операцию, которая позволила бы мне избежать этого — выполните итерацию по массиву, проверьте, является ли значение ниже 15, если оно ниже 15, затем установите его равным 15, в противном случае оно выше 75, если оно выше 75, тогда установите значение равным 75.

Любая помощь приветствуется.

Комментарии:

1. Какой язык? И как еще вы хотели бы это сделать, кроме сравнения каждого элемента с выбранным диапазоном?

2. Почему именно вы не можете перебирать массив, чтобы сделать это?

3. Не удается выполнить цикл из-за большого размера массива. Кроме того, это обработка изображений, и диапазон меняется (15-75) очень быстро. Я надеялся, что где-то есть API, который взаимодействует с Java Native и выполняет манипуляции быстрее.

4. @RavSom: это Java, а не JAVA. Нет необходимости кричать 🙂

5. о, извините, не понял, что все заглавные буквы кричали. Должным образом извиняюсь.

Ответ №1:

Даже если есть какая-то сторонняя библиотека, которая обладает этой функциональностью, она просто будет выполнять точно такую же операцию — цикл по массиву. По сути, вам нужно что-то вроде:

 for (int i = 0; i < array.length; i  )
{
    array[i] = clamp(array[i], 15, 70);
}

...

public static byte clamp(byte value, byte min, byte max)
{
    return value < min ? min
         : value > max ? max
         : value;
}
  

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

Комментарии:

1. Спасибо за ваш ответ. Согласен, это основная цель. Однако скорость операции значительна, и если я сделаю это таким образом, это будет скомпрометировано, учитывая размер данных массива (20 МБ)

2. @RavSom: Но где вы это выполняете? Вы пробовали это, чтобы увидеть, достаточно ли быстр простой подход?

3. @RavSom: я только что попробовал, и на моем ноутбуке я могу сжать массив размером 20 МБ примерно за 38 МС (т. Е. 1000 раз за 38 секунд). Это достаточно быстро для вас?

Ответ №2:

Вы можете использовать метод Guava Lists.transform для обновления значений. Однако это приведет к тому, что новый массив не обновит значения в существующем массиве.

 List<Byte> list = Lists.newArrayList(myArray);
List<Byte> trans = Lists.transform(list, new Function<Byte, Byte>(){...});
byte[] bytes = Bytes.toArray(trans);
  

Однако, учитывая то, что вы пытаетесь сделать, я бы предложил просто перебирать значения.

Ответ №3:

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

Я бы попробовал что-то вроде этого:

 final int n = array.length;
for (int i = 0; i < n; i  ) {
  int val = array[i];
  if (val < 15) {
    array[i] = 15;
  } else if (val > 75) {
    array[i] = 75;
  }
}
  

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

Ответ №4:

Вместо проверки диапазонов, как предлагает Джон Скит, вы могли бы создать таблицу поиска для каждого из 256 возможных байтов, которые может иметь байт, т. Е. Что-то вроде

 {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,17,18,...,69,70,70,70,70,...}


for (int i = 0; i < len; i  )
{
    array[i] = lookup[array[i]];
}
  

В C: меньше ветвлений, намного быстрее. В Java: к сожалению, не быстрее, даже немного медленнее, возможно, потому, что проверки диапазона массива Java съедают полученную скорость; и поскольку байты Java всегда подписаны, это немного сложнее, чем показано выше.

В C вы могли бы даже сделать это для 16-битных полусловов, снова сделав его быстрее. (Вероятно, с коэффициентом 2)

РЕДАКТИРОВАТЬ: К моему собственному стыду, я должен признать, что надлежащее тестирование показало, что таблица поиска не работает быстрее в C. Мои первые результаты, вероятно, были искажены оптимизацией компилятора. Во всяком случае, по крайней мере, на моей машине,

 if (array[i]<15) array[i]=15;
else if (array[i]>70) array[i]=70;
  

заметно быстрее, чем при использовании троичного оператора.