How to get a list of decimal numbers "hidden" in binary number in PHP?

Firstly, I really apologize for the poorly written title of this question. Therefore, please, for someone with native English, change the name accordingly. My question is pretty simple:

I use an integer to store several types of one element. For instance:

TYPE A = 1 TYPE B = 2 TYPE C = 4 TYPE D = 8 TYPE E = 16 etc... 

Now the element in the database has a value of type 14, which means that it was assigned to TYPE B + C + D. If it had a value of type, for example, 9, it would mean that it was assigned to type A + D.

I need a function that I would put with an integer of the same type, and this function will return an array of integer types.

I could iterate over all integers and compare them with a number, but with what I am using now, but I am looking for a more efficient way if it exists?

Thanks in advance for your help.

+4
source share
4 answers

Here is a function without any loops (mainly for the pleasure of it :)):

 function getTypes($int) { $types = array('Type A','Type B','Type C','Type D','Type E');//defining types $t = array_reverse(str_split(decbin($int)));//converting $int to an array of bits $types = array_slice($types,0,ceil(log($int,2)));//slicing the array to the same size as number of bits in the $int $t = array_combine($types,$t);// Creating a new array where types are keys and bits are values return array_keys($t,1);// returning an array of keys which have a value of 1 } 

However, this does not mean that it is effective. If you use a bitmask, you are better off checking the values ​​using bitwise operators such as bitwise and (&). For example, if you want to check if your integer contains Type D and Type E, you should do

 if ($integer & 8 & 16) 

To check each individual type, I would request a loop with a bit-break operator

 function getTypes($int) { $result = array(); $types = array('Type A','Type B','Type C','Type D','Type E'); foreach($types as $type) { if ($int & 1)//checking if last bit is 1 (exactly the same as if($int%2) ) $result[]=$type; $int>>=1;//shifting integer bits to the right (exactly the same as $int = $int / 2) } return $result; } 
+1
source

Like this? http://codepad.org/AzgdPsL1

To explain what is going on:

  • I am creating an $types array of all valid types that exist between ranges from 1 to $max_bit .
  • The loop, while the number is greater than 0, it becomes bitwise AND with 1. If it turns out that the value is true, it means that the LSB is set, so type at the head of the $type array refers to this number. The current type is added to the returned array.
  • Then the number is shifted to the right by one bit.

     <?php function num2type( $num) { $max_bit = 5; $types = array_combine( range( 1, $max_bit), range( ord( 'A'), ord( 'A') + $max_bit - 1)); $return = array(); while( $num > 0) { $current_type = array_shift( $types); if( $num & 0x1) { $return[] = chr( $current_type); } $num = $num >> 1; } return $return; } var_dump( num2type( 8)); // array(1) { [0]=> string(1) "D" } var_dump( num2type( 31)); var_dump( num2type( 14)); 

Output (for 31):

 array(5) { [0]=> string(1) "A" [1]=> string(1) "B" [2]=> string(1) "C" [3]=> string(1) "D" [4]=> string(1) "E" } 

Output for 14:

 array(3) { [0]=> string(1) "B" [1]=> string(1) "C" [2]=> string(1) "D" } 
+1
source
 $a = 10; $scan = 1; $result = array(); while ($a >= $scan){ if ($a & $scan) $result[] = $scan; $scan<<=1; //just a bit shift } var_dump($result); 
+1
source
 function check_flag($field, $bit) { return (($field | $bit) === $field) ? TRUE : FALSE; } $types = array('A' => 1, 'B' => 2, 'C' => 4, 'D' => 8, 'E' => 16); $db_value = 14; var_dump(check_flag($db_value, $types['B'])); 

... just make sure you select the value from the database as an integer.

Edit: now that I am reading, you need all the types that are installed, here are some more logic:

 $set = array(); foreach ($types as $key => $value) if (check_flag($db_value, $value)) $set[] = $key; 
+1
source

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


All Articles