I have an array of integers, where each integer value is a 'group membership' bitmask. For example, array(1, 4, 5) is interpreted as:
The first element (1) is a member of Group 0 (i.e. 2**0)
The second element (4) is a member of Group 2 (i.e. 2**2)
The third element (5) is a member of Groups 0 and 2 (i.e. 2**0 + 2**2)
So, my question is, how can I efficiently count the number of members in each of the groups?
My starting point would be to do something like this:
$count = array();
for ($i=0; $i<64; $i++) {
$count[$i] = 0;
$comparator = 2**$i;
foreach ($array as $value) {
if ($comparator & $value) $count[$i]++;
}
}
That seems like a long winded way to go about things. If I have 1,000 elements in the array, I am doing 64 X 1000 iterations.
Is there an easier way to go about this? Using an advanced array technique, for example, or a php extension for bitwise operations?
If you do not really need to keep 64 groups, and 62 is enough for you (or 30 on 32-bit platform), following code will help you:
$count = array();
$data = array(1, 4, 5, 7);
foreach ($data as $x)
for ($i=0, $j = 1; $j <= $x; $i++, $j <<= 1)
if($x & $j)
$count[$i]++;
print "count=";
print_r($count);
Related
I'm making a small function in PHP that, like described in the title, need an array filled with random numbers inside a specified range, the numbers MUST repeat within it. As an example, filling an array with 20 random numbers between 1 and 10 should result in something like this:
Array = [2,5,8,2,8,5,3,9,6,3,4,6,3,1,2,1,2,3,7,1]
This code creates an array ($arr = array();) and then 20 times (the loop) pushes a random value on the end of the array.
The values are generated by random_int function that generates numbers in the given range (inclusively).
<?php
$arr = array();
for ($i = 0; $i < 20; $i++) {
array_push($arr, random_int(1, 10));
}
The source of randomness is quite good (depending on the system).
If you want such random number array generator as a function, do this:
<?php
function random_ints($count, $min, $max) {
$arr = array();
for ($i = 0; $i < $count; $i++) {
array_push($arr, random_int($min, $max));
}
}
I have the following code to pick $n elements from an array $array in PHP:
shuffle($array);
$result = array_splice($array, 0, $n);
Given a large array but only a few elements (for example 5 out of 10000), this is relatively slow, so I would like to optimize it such that not all elements have to be shuffled. The values must be unique.
I'm looking fo the most performant alternative. We can assume that $array has no duplicates and is 0-indexed.
$randomArray = [];
while (count($randomArray) < 5) {
$randomKey = mt_rand(0, count($array)-1);
$randomArray[$randomKey] = $array[$randomKey];
}
This will provide exactly 5 elements with no duplicates and very quickly. The keys will be preserved.
Note: You'd have to make sure $array had 5 or more elements or add some sort of check to prevent an endless loop.
This function performs a shuffle on only $n elements where $n is the number of random elements you want to pick. It will also work on associative arrays and sparse arrays. $array is the array to work on and $n is the number of random elements to retrieve.
If we define the $max_index as count($array) - 1 - $iteration.
It works by generating a random number between 0 and $max_index. Picking the key at that index, and replacing its index with the value at $max_index so that it can never be picked again, as $max_index will be one less at the next iteration and unreachable.
In summary this is the Richard Durstenfeld's Fisher-Yates shuffle but operating only on $n elements instead of the entire array.
function rand_pluck($array, $n) {
$array_keys = array_keys($array);
$array_length = count($array_keys);
$max_index = $array_length -1;
$iterations = min($n, $array_length);
$random_array = array();
while($iterations--) {
$index = mt_rand(0, $max_index);
$value = $array_keys[$index];
$array_keys[$index] = $array_keys[$max_index];
array_push($random_array, $array[$value]);
$max_index--;
}
return $random_array;
}
The trick is to use a variation of shuffle or in other words a partial shuffle.
performance is not the only criterion, statistical efficiency, i.e unbiased sampling is as important (as the original shuffle solution is)
function random_pick( $a, $n )
{
$N = count($a);
$n = min($n, $N);
$picked = array_fill(0, $n, 0); $backup = array_fill(0, $n, 0);
// partially shuffle the array, and generate unbiased selection simultaneously
// this is a variation on fisher-yates-knuth shuffle
for ($i=0; $i<$n; $i++) // O(n) times
{
$selected = mt_rand( 0, --$N ); // unbiased sampling N * N-1 * N-2 * .. * N-n+1
$value = $a[ $selected ];
$a[ $selected ] = $a[ $N ];
$a[ $N ] = $value;
$backup[ $i ] = $selected;
$picked[ $i ] = $value;
}
// restore partially shuffled input array from backup
// optional step, if needed it can be ignored, e.g $a is passed by value, hence copied
for ($i=$n-1; $i>=0; $i--) // O(n) times
{
$selected = $backup[ $i ];
$value = $a[ $N ];
$a[ $N ] = $a[ $selected ];
$a[ $selected ] = $value;
$N++;
}
return $picked;
}
NOTE the algorithm is strictly O(n) in both time and space, produces unbiased selections (it is a partial unbiased shuffling) and produces output which is proper array with consecutive keys (not needing extra array_values etc..)
Use example:
$randomly_picked = random_pick($my_array, 5);
// or if an associative array is used
$randomly_picked_keys = random_pick(array_keys($my_array), 5);
$randomly_picked = array_intersect_key($my_array, array_flip($randomly_picked_keys));
For further variations and extensions of shuffling for PHP:
PHP - shuffle only part of an array
PHP shuffle with seed
How can I take n elements at random from a Perl array?
This will only show benifits for small n compared to an array shuffle, but you could
Choose a random index r n times, each time decreasing the limit by 1
Adjust for previously used indices
Take value
Store used index
Pseudocode
arr = []
used = []
for i = 0..n-1:
r = rand 0..len-i
d = 0
for j = 0..used.length-1:
if r >= used[j]:
d += 1
arr.append($array[r + d])
used.append(r)
return arr
You could generate n-times a random number with mt_rand() and then fill these values in a new array. To go against the case where the same index gets returned twice we use the actual returned index to fill the new array and check always if the index exists in the new array, if so we use while to loop through it as long as we get a duplicate index. At the end we use array_values() to get a 0-indexed array.
$count = count($array) - 1;
$new_array = array();
for($i = 0; $i < $n; $i++) {
$index = mt_rand(0, $count);
while(isset($new_array[$index])) {
$index = mt_rand(0, $count);
}
$new_array[$index] = $array[$index];
}
$new_array = array_values($new_array);
I wonder why everyone here make it so complicated?
Here's the fastest and simplest way:
$randomArray = array_rand(array_flip($array), $n);
How to the find the number of array elements present in the array between 2 values in PHP .
lets say this is my array =>
$a = array(1,2,3,5,10);
I want to find the length of array between 2 values i.e. 2 and 10. So the answer will be 3 in the case. If the highest value to be searched is present in the array it should be added in count.
also length of array between 2 and 9 is 2.
Hope I am clear with my question. Any help would be appreciated.
Use array_filter() to filter the array down to the matching elements, then use count() on the resulting filtered array.
$a = array(1,2,3,5,10);
print count(array_filter($a, function($e) {return ($e>=2 && $e<=10);}));
Hope that helps.
Note: The syntax I've used here, with the embedded function, requires PHP v5.3 or higher.
[EDIT]
Turn it into a simple callable function:
$a = array(1,2,3,5,10);
print countInRange(2,10);
function countInRange($min,$max) {
return count(array_filter($a, function($e) use($min,$max) {return ($e>=$min && $e<=$max);}));
}
See PHP manual for more info on array_filter() function.
$count = 0;
for( $i = 0; $i < count($a); $i++ ) {
if( $a[$i] <= $max && $a[$i] >= $min )
$count++;
}
echo $count;
$count = 0;
$min = 2;
$max = 10;
$a = array(1,2,3,5,10);
foreach($a as $val) {
if($val > $min && $val <= $max) ++$count;
}
This should work, right? At least it will find all numbers, which are higher than your minimum but smaller/equal to your maximum.
Of course this also means, that an array of 1, 2, 9, 5 would return 2, since both 9 and 5 are greater than 2 and smaller than 10.
I need to create an array like this:
$array = array(array(1,1,1,0,0,0,1,1), array(1,1,1,1,0,0,1,0));
but with all combinations of 1 and 0.
I wish to do this automatically, so I was thinking a for loop would be the best idea.
In other words the inner arrays should be all combos like 0,0,0,0,0,0,0,0 then 0,0,0,0,0,0,0,1 then 0,0,0,0,0,0,1,0 then 0,0,0,0,0,0,1,1. for all combos.
I started like this:
$array = array();
for($i =0;$i<100; $i++){
$array[$i] = 0;
}
How do I get this to do what I am trying to do?
Use decbin to convert your counter to binary.
str_pad allows you to pad strings, in this case I'm 0-padding it to a length of 8 bits.
$array = array();
for($i =0;$i<100; $i++){
$array[$i] = str_pad(decbin($i), 8, "0", STR_PAD_LEFT);;
}
var_dump($array);
Demo
This will print out an array of all binary variations from 00000000 to 11111111 where each one is in it's own array of chars.
$array = array();
for ($i = 0; $i < 256;)
{
$array[] = str_split(sprintf('%08d', decbin($i++)));
}
print_r($array);
See example
I am trying to use a function whereby I see how tall (y axis) a two dimensional array is in PHP. How would you suggest that I do this? Sorry, I am new to PHP.
max(array_map('count', $array2d))
If the y-axis is the outer array, then really just count($array). The second dimension would just be count($array[0]) if it's uniform.
A multi-dimensional array is simply an array of arrays -- it's not like you've blocked out a rectangular set of addresses; more like a train where each car can be stacked as high as you like.
As such, the "height" of the array, presumably, is the count of the currently largest array member. #phihag has given a great way to get that (max(array_map(count, $array2d))) but I just want to be sure you understand what it means. The max height of the various arrays within the parent array has no effect on the size or capacity of any given array member.
$max = 0;
foreach($array as $val){
$max = (count($val)>$max?count($val):$max)
}
where $max is the count you are looking for
In my application I have used this approach.
$array = array();
$array[0][0] = "one";
$array[0][1] = "two";
$array[1][0] = "three";
$array[1][1] = "four";
for ($i=0; isset($array[$i][1]); $i++) {
echo $array[$i][1];
}
output: twofour
Probably, this is not the best approach for your application, but for mine it worked perfectly.
To sum up the second dimension, use count in a loop:
$counter = 0;
foreach($var AS $value) {
$counter += count($value);
}
echo $counter;
1.dimension:
count($arr);
2.dimension:
function count2($arr) {
$dim = 0;
foreach ($arr as $v) {
if (count($v) > $dim)
$dim = count($v);
}
return $dim;
}
As it is possible to have each array / vector of different length (unlike a mathematical matrix) you have to look for the max. length.