2014-12-17 2 views
5

У меня есть 32-разрядное целое число, используемое для битмаски, и массив с 32 значениями. Как получить только те значения из массива, какие индексы соответствуют позициям ненулевых битов в битовой маске?Получить значения массива на основе битмаски в PHP

Например, скажем, что битовая маска составляет 49152, что составляет 1100000000000000 в двоичном формате. Поэтому я должен принимать значения элементов с индексами 14 и 15 из массива.

ответ

1

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

  1. Это явное и использует слова, а не математические ухищрения, чтобы получить работу, и
  2. работы в ситуациях, когда вы не можете предположить, лежащий в основе реализации 2s дополнения, но все еще хотят «думать» таким образом. (попробуйте «хранение» битмаски в PHP и думать, что они будут работать в JavaScript)

Пожалуйста, прочтите комментарии и осуществлять @Paebbels решение. Разница в производительности почти 7x, поэтому на самом деле это использовать, если она не будет использоваться очень часто.

Он использует base_convert, чтобы преобразовать базовое целое число 10 в основание 2, разбивает строку на массив символов, меняет массив и затем выполняет итерации по ней, ища 1 с.

$mask = 49152; // 0xC000 

// Find which positions in the mask contain a '1' 
$bitArray = array_reverse(str_split(base_convert($mask, 10, 2))); 

foreach($bitArray as $k => $v) { 
    if($v) { 
     echo $k . " is a one\n"; 
    } 
} 

Выход:

14 является одним

15 представляет собой один

В качестве функции:

function extractElements($mask, array $input) 
{ 
    $output = array(); 
    $bitArray = array_reverse(str_split(base_convert($mask, 10, 2))); 

    foreach($bitArray as $k => $v) { 
     if($v && isset($input[$k])) { 
      $output[] = $input[$k]; 
     } 
    } 

    return $output; 
} 

$mask = 76; // 0x4C 
$input = [ 
    'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight' 
]; 

print_r(extractElements($mask, $input)); 

Выход:

Массив ( [0] => Три 1 => Четыре [2] => Семь )

+0

Извините, но это решение потребляет массу памяти и циклы процессора для работы простых битовых сдвигов и бит-сравнений. – Paebbels

+0

_ Массы памяти_? Не так уж плохо для 32-битной целочисленной маски. Если у вас нет требований в режиме реального времени (.. в PHP ..) или вы неоднократно вызываете это, то это решение подходит. В противном случае, я уверен, что люди найдут ваш ответ полезным. –

+0

Мое решение: 3 слова á 4 байта = 12 байтов {m, j, i}, у него нет инструкций по вызову. - Ваше решение преобразует маску из int в строку; использует базовое преобразование, основанное на двойных значениях (строка для double, base convert, to string conversion); после этого используется строковая операция (str_split) и, наконец, строковая обратная операция. Это только начальные берега ... На каждой итерации вы получаете доступ к хеш-списку и вызываете функцию isset для простого сравнения бит. В вашем коде используется 35 инструкций по вызову. Память: каждый символ промежуточной строки хранится в 2 байтах (UTF-16) => 64 байта. – Paebbels

6

Вам нужно будет зайти на 32 шага по вашей маске и протестировать его на «1», если этот бит установлен, вы можете скопировать элемент в результирующий массив.

псевдокод:

m = 0x00000001 
j = 0 
for i in 0 to 31 loop 
    if ((mask & m) = m) then // bit is set in mask 
    result(j++) := input(i) 
    end if 
    m := m << 1  // shift left by 1 or multiply by 2 
end loop 
+0

Как вы можете критиковать реальный ** ** PHP код Джеффа Ламберта, когда все вы предлагаете _pseudocode_, который не рассматривает поставленный вопрос? –

+0

Как отметил Джефф, мой предложенный алгоритм (который он реализовал) в 7 раз быстрее! – Paebbels

+0

Это даже не PHP. #JustSaying –

Смежные вопросы