Erlang битовая индексация
В настоящее время я пытаюсь выучить erlang, и я пытаюсь выполнить операцию над определенными индексами массива, хранящегося в битовом массиве или int. Если в позиции 0, индекс в массиве в этой позиции не используется.
Итак, представьте следующее:
Example the array is: [1, 3, 5, 42, 23]
My bit array is: 21 = 10101 in binary
so I'm using indicies 1,3,5
so I'm calling a function on [1, 5, 23]
моя функция имеет форму
my_function(Array, BitArray) ->
SubArray = get_subarray_from_bitarray(Array, BitArray),
process_subarray(SubArray).
И мне нужна помощь с get_subarray_from_bitarray(). Я знаю, что erlang имеет специальный синтаксис вокруг битовых строк (что-то вроде <<>>), так есть ли эффективный способ индексации в битовый массив, чтобы получить указатели?
2 ответа
В большинстве случаев Эрланг работает со списками и рекурсией, поэтому я считаю, что идиоматично проходить каждый бит отдельно, а не пытаться индексировать каждый бит итеративным способом.
Документация о том, как работать с цепочками битов, находится здесь. Чтобы создать цепочку из числа 21, мы можем написать <<21>>
, Так как тип по умолчанию для члена двоичного файла - целое число, а размер по умолчанию для целого числа - 8, это приведет к цепочке битов, которая выглядит как 00010101
, Если вы хотите специально получить последние N байтов значения <<Value:N>>
, Чтобы получить последние 5 битов из 21, можно сказать, <<21:5>>
который даст 10101
,
Я написал следующий модуль, чтобы делать то, что вы хотите:
-module(bitmask).
-export([get_subarray_from_bitarray/2]).
get_subarray_from_bitarray(Bitstring, List) ->
get_subarray_from_bitarray_loop(Bitstring, List, []).
get_subarray_from_bitarray_loop(_Bits, [], Gathered) ->
io:format("End of list~n", []),
lists:reverse(Gathered);
get_subarray_from_bitarray_loop(<<>>, _Others, Gathered) ->
io:format("End of bitstring~n", []),
lists:reverse(Gathered);
get_subarray_from_bitarray_loop(<<Bit:1, Rest/bitstring>>, [Item | Others], Gathered) ->
io:format("Bit: ~w ~n", [Bit]),
case Bit of
1 -> get_subarray_from_bitarray_loop(Rest, Others, [Item | Gathered]);
0 -> get_subarray_from_bitarray_loop(Rest, Others, Gathered)
end.
Первые 2 предложения возвращают окончательный список, когда у вас заканчиваются биты или элементы в списке. Важный битовый синтаксис находится в заголовке последнего предложения, <<Bit:1, Rest/bitstring>>
, Это устанавливает значение Bit
к значению первого бита в цепочке битов, и Rest
к остальной части цепочки. В зависимости от значения Бита мы решаем, добавлять ли текущий элемент в список или нет.
Пример вызова ниже:
> bitmask:get_subarray_from_bitarray(<<21:5>>, [1, 3, 5, 42, 23]).
Bit: 1
Bit: 0
Bit: 1
Bit: 0
Bit: 1
End of list
[1,5,23]
> bitmask:get_subarray_from_bitarray(<<31>>, [1, 3, 5, 42, 23]).
Bit: 0
Bit: 0
Bit: 0
Bit: 1
Bit: 1
End of list
[42,23]
> bitmask:get_subarray_from_bitarray(<<5:3>>, [1, 3, 5, 42, 23]).
Bit: 1
Bit: 0
Bit: 1
End of bitstring
[1,5]
Возможная реализация get_subarray_from_bitarray/2
функция может быть:
get_subarray_from_bitarray(Array, BitArray) ->
gsb(Array, BitArray, []).
gsb(_, 0, R) -> lists:reverse(R);
gsb([A1|A2], B, R) ->
NextR = if B band 1 /= 0 ->
[A1|R];
true ->
R
end,
gsb(A2, B div 2, NextR).
Я уверен, что было бы очень хорошо с пониманием списка тоже. Оставлено как упражнение для читателя:)