all combination of x pow y in php - php

I have an array having three element $base =(#m, #f,#p)
I have a second array having any number of element like $var = (s1, s2)
Now i need to create all possible combinations depending only on the base array. The formula I found is x pow y.
In this example my base array has three element and $var has 2, so pow(3, 2) is 9. I need these nine combinations. i.e
#m#m #m#f #m#p
#f#m #f#f #f#p
#p#m #p#f #p#p
The number of elements in the 2nd array is in effect the length of the generated combinations. As in this example the length of the 2nd array is 2 so all generated strings have length 2.

You can use a recursive function like this:
// input definition
$baseArray = array("#m", "#f", "#p");
$varArray = array("s1", "s2", "s3");
// call the recursive function using input
$result = recursiveCombinations($baseArray, sizeof($varArray));
// loop over the resulting combinations
foreach($result as $r){
echo "<br />combination " . implode(",", $r);
}
// this function recursively generates combinations of #$level elements
// using the elements of the $base array
function recursiveCombinations($base, $level){
$combinations = array();
$recursiveResults = array();
// if level is > 1, get the combinations of a level less recursively
// for level 1 the combinations are just the values of the $base array
if($level > 1){
$recursiveResults = recursiveCombinations($base, --$level);
}else{
return $base;
}
// generate the combinations
foreach($base as $baseValue){
foreach($recursiveResults as $recursiveResult){
$combination = array($baseValue);
$combination = array_merge($combination, (array)$recursiveResult);
array_push($combinations, $combination);
}
}
return $combinations;
}
Working codepad demo

<?php
$strs = Array("some", "thing", "here");
$poss = Array(1, 2);
$new = Array();
for($i = 0; $i < pow(count($strs), count($poss)); $i++) {
for($j = 0; $j < count($strs); $j++) {
$new[$i] = $strs[($i%count($strs))] . " " . $strs[$j];
}
}
print_r($new);
?>
Working codepad link(for given example).
LINKS
pow(4, 3)
pow(4, 2)
pow(3, 5)

Related

PHP array get the different number

I have the following array:
$array = [2,2,5,2,2];
I would like to get the number which is different from the others, for example all the numbers are 2 except the number 5. So Is there anyway to get the different number using any array method or better solution? My solution is:
$array = [2,2,5,2,2];
$array1 = [4,4,4,6,4,4,4];
$element = -1;
$n = -1;
$count = 0;
for($i=0; $i<count($array1); $i++) {
if($element !== $array1[$i] && $element !== -1 & $count==0) {
$n = $array1[$i];
$count++;
}
$element = $array1[$i];
}
dd($n);
You can use array_count_values for group and count same value like:
$array = [2,2,5,2,2];
$countarray = array_count_values($array);
arsort($countarray);
$result = array_keys($countarray)[1]; // 5
Since you only have two numbers, you will always have the number with the least equal values ​​in second position
Reference:
array_count_values
array_keys
A small clarification, for safety it is better to use arsort to set the value in second position because if the smallest number is in first position it will appear as the first value in the array
Sorting Arrays
You can user array_count_values which returns array with item frequency.
Then use array_filter to filter out data as follow:
$arrayData = [2,2,2,5];
$filterData = array_filter(array_count_values($arrayData), function ($value) {
return $value == 1;
});
print_r($filterData);
Inside array_filter(), return $value == 1 means only get the data with 1 frequency and thus filter out the other data.
<?php
function UniqueAndDuplicat($array){
$counts = array_count_values($array);
foreach ($counts as $number => $count) {
print $number . ' | ' . ($count > 1 ? 'Duplicate value ' : 'Unique value ') . "\n";
}
}
$array1 = [2,2,5,2,2];
$array2 = [4,4,4,6,4,4,4];
UniqueAndDuplicat($array1);
//output: 2 | duplicate value 5 | Unique value
UniqueAndDuplicat($array2);
//output: 4 | duplicate value 5 | Unique value
?>
Use this function to reuse this you just call this function and pass an Array to this function it will give both unique and duplicate numbers.
If you want to return only Unique number then use the below code:
<?php
function UniqueAndDuplicat($array){
$counts = array_count_values($array);
foreach ($counts as $number => $count) {
if($count == 1){
return $number;
}
}
}
$array1 = [2,2,5,2,2];
$array2 = [4,4,4,6,4,4,4];
echo UniqueAndDuplicat($array1); // 5
echo "<br>";
echo UniqueAndDuplicat($array2); // 6
?>

PHP subtract the elements of an array within the elements

I have an array [4,3,5,5,7,6] and I want to loop through the sorted one and subtract the highest value from the preceding value, then subtract the remainder from the value behind it and so on, then in the end, I need one final value that comes when the loop is completed.
For example
Above array will be sorted like
Array
(
[0] => 3
[1] => 4
[2] => 5
[3] => 5
[4] => 6
[5] => 7
)
Now I want to find the difference between arr[5] and arr[4], the result will be 1, then subtract the result from arr[3] and so on till the loop is completed
This is what I tried but it doesn't seem to work
for ($i = count($a)-1; $i >0; $i--){
echo $result = $a[$i] - $a[$i-1];
echo "<br />";
if($result > 0) {
if($result > $a[$i-2]) {
echo $result = $result - $a[$i-2];
} else {
}
}
I think there is a more simple and fast way to achieve this:
$array = [4, 3, 5, 5, 7, 6];
rsort($array);
$result = $array[0] - $array[1];
for($i = 2, $count = count($array); $i < $count; $i++){
$result = $array[$i] - $result;
}
print($result);
output:
0
Do you wish this way?
$a = [1,1,1,3,1,7];
$result = null;
for ($i = count($a)-1; $i >0; $i--){
if($result == null)
$result = $a[$i-1];
echo $result = $a[$i] - $result;
echo "<br />";
if($result == 0) break;
}
My first answer was wrong, i see you need to discard 2 keys after the first substraction.
This does the job:
<?php
$array = [3,4,5,5,6,7];
$reverse = array_reverse($array);
if (count($reverse) > 1) {
$first = $reverse[0] - $reverse[1];
} else {
//code should stop
}
$result = $first;
for ($i = 2; $i < count($reverse); $i++) {
$result = $reverse[$i] - $result;
}
echo $result;
Ouputs 0, just as in your example. And of course this code still needs check to see if the key of the array does exist while iterating
$numbers = [4,3,5,5,7,6];
sort($numbers);
$numbers = array_reverse($numbers);
$first = array_shift($numbers);
$second = array_shift($numbers);
$result = array_reduce($numbers, function ($carry, $current_item) {
return $current_item - $carry;
}, ($first - $second));
echo $result;
To get the expected output you are seeking you can use rsort to sort descending and start with the highest number. The first 2 elements are subtracted to get the starting value. Loop through the remainder to get your result.
Here's how you can achieve that:
$a = [4, 3, 5, 5, 7, 6]; // Your unsorted array
rsort($a); // Sort array by descending of largest to smallest
$result = $a[0] - $a[1]; // Initial subtraction of first two values
unset($a[0], $a[1]); // Remove from array so it won't loop through
foreach ($a as $_a) { // Loop through remainder and subtract difference
$result = $_a - $result;
}
echo $result; // Show your result
Yields:
0
If you care about reindexing due to the unset you can simply add an extra line after that:
$a = array_values($a); // Reindexes array starting at 0 if you desire

Reducing an array

I have an array that goes from '00:00:00' to '23:59:59', something like this ['00:00:00', '00:00:01' ... '23:59:59'].
I need to write a function to reduce the array length into n items but always keeping the first and the last element.
An example:
reduce_into($array, 3) -> ['00:00:00', '12:00:00', '23:59:59']
Note that the array must be "balanced", that means that when I reduce it into 3 elements it will return the first, the one in the middle and the last one.
Here's the code:
function getnewarray($t,$i)
{
$newArr[0] = $t[0];
$a = 1;
$masterdivby = $divby = count($t) / ($i-1);
$ni = $i-2;
while($a <= $ni)
{
$newArr[$a] = $t[$divby];
$divby = $masterdivby + $divby;
$a++;
}
$newArr[$i] = $t[count($t) - 1];
return $newArr;
}
?>

Efficiently pick n random elements from PHP array (without shuffle)

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

Given an array of integers, what's the most efficient way to get the number of other integers in the array within n?

Given the following array:
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
And assuming $n = 2, what is the most efficient way to get a count of each value in the array within $n of each value?
For example, 6 has 3 other values within $n: 5,7,7.
Ultimately I'd like a corresponding array with simply the counts within $n, like so:
// 0,0,1,2,2,5,6,7,7,9,10,10 // $arr, so you can see it lined up
$count_arr = array(4,4,4,4,4,3,3,4,4,4, 2, 2);
Is a simple foreach loop the way to go? CodePad Link
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
$n = 2;
$count_arr = array();
foreach ($arr as $v) {
$range = range(($v-$n),($v+$n)); // simple range between lower and upper bound
$count = count(array_intersect($arr,$range)); // count intersect array
$count_arr[] = $count-1; // subtract 1 so you don't count itself
}
print_r($arr);
print_r($count_arr);
My last answer was written without fully groking the problem...
Try sorting the array, before processing it, and leverage that when you run through it. This has a better runtime complexity.
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
asort($arr);
$n = 2;
$cnt = count($arr);
$counts = array_pad(array(), $cnt, 0);
for ($x=0; $x<$cnt; $x++) {
$low = $x - 1;
$lower_range_bound = $arr[$x]-$n;
while($low >= 0 && ($arr[$low] >= $lower_range_bound)) {
$counts[$x]++;
$low--;
}
$high = $x + 1;
$upper_range_bound = $arr[$x]+$n;
while($high < $cnt && $arr[$high] <= $upper_range_bound) {
$counts[$x]++;
$high++;
}
}
print_r($arr);
print_r($counts);
Play with it here: http://codepad.org/JXlZNCxW

Categories