Get bitmask based array values โ€‹โ€‹in PHP

I have a 32-bit integer used for bitmask and an array with 32 values. How to get only those values โ€‹โ€‹from the array, which indexes correspond to the positions of nonzero bits in the bitmask?

For example, let's say that the bitmask is 49152, which is equal to 1100000000000000 in binary format. Therefore, I must accept the values โ€‹โ€‹of elements with indices 14 and 15 from the array.

+8
source share
3 answers

Here is some PHP code for you, but please note that it is rather inefficient. I used this algorithm because:

  • He is explicit and uses words, not mathematical tricks, to do the job, and
  • It works in situations where you cannot accept the basic implementation of 2s, but still want to "think" in this way. (try to "save" the bitmasks in PHP and think that they will work in JavaScript )

Read the comments and contribute @Paebbels solution. The difference in performance is almost 7x, so actually use it only if it will not be used very often.

It uses base_convert to convert base number 10 to base 2, splits the string into an array of characters, changes the array and then iterates over it, looking for 1 s.

 $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"; } } 

Conclusion:

14 is one

15 is one

As a function:

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

Conclusion:

Array ([0] => Three 1 => Four [2] => Seven)

0
source

You will need to take 32 steps on your mask and test it at "1", if this bit is set, you can copy the element to the resulting array.

Pseudocode:

 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 
+6
source

I have implemented a function that suits your needs, and additionally:

  • can handle a smaller or larger data type

  • saving values, not just indexes


 function extractMask($mask, &$idxs, &$values) { for($i = 0, $valueToCompare = 1; $valueToCompare <= $mask; $i++, $valueToCompare <<= 1) { if ($mask & $valueToCompare){ $idxs[] = $i; $values[] = $valueToCompare; } } } // usage: extractMask(49152, $idxs, $values); // results: var_dump($idxs); var_dump($values); 

For an impression, here is a snippet of JS code:

 function extractMask(mask) { var result = {idxs: [], values: []}; for(i = 0, valueToCompare = 1; valueToCompare <= mask; i++, valueToCompare <<= 1) { if (mask & valueToCompare){ result.idxs.push(i); result.values.push(valueToCompare); } } return result; } //====================== UI ========================== var anchor = document.getElementsByTagName("a")[0]; var input = document.getElementsByTagName("input")[0]; anchor.addEventListener("click", function(e) { var result = extractMask(input.value); console.log(result); }); input.addEventListener("keyup", function (e) { if (e.keyCode == 13) { var result = extractMask(input.value); console.log(result); } }); //==================================================== 
 <input value="49152" /> <a href="#">calculate</a> 
0
source

Source: https://habr.com/ru/post/1209404/


All Articles