#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;
заметно быстрее, чем при использовании троичного оператора.