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).

Я уверен, что было бы очень хорошо с пониманием списка тоже. Оставлено как упражнение для читателя:)

Другие вопросы по тегам