Get all unique combinations from array for a given number of elements - php

I wanted to have a way to get all combinations for all given numbers with given array length.
In my project the array size usually is 7. So I write a test code like this to see if I can get all needed combinations. The important part is every result array must be unique and maximum array size must be 7.
<?php
$numbers = [1, 2, 3, 4, 5, 6, 7];
$arraysize = 7;
$subset = [];
$count = count($numbers);
for ($i = 0; $i < $count; $i++) {
$subset[] = $numbers[$i];
}
for ($i=0; $i < $count; $i++) {
for ($j=$i; $j < $count; $j++) {
$subset[] = $numbers[$i] . $numbers[$j];
}
}
for ($i=0; $i < $count; $i++) {
for ($j=$i; $j < $count; $j++) {
for ($k=$j; $k < $count; $k++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k];
}
}
}
for ($i=0; $i < $count; $i++) {
for ($j=$i; $j < $count; $j++) {
for ($k=$j; $k < $count; $k++) {
for ($l=$k; $l < $count; $l++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l];
}
}
}
}
for ($i=0; $i < $count; $i++) {
for ($j=$i; $j < $count; $j++) {
for ($k=$j; $k < $count; $k++) {
for ($l=$k; $l < $count; $l++) {
for ($m=$l; $m < $count; $m++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l] . $numbers[$m];
}
}
}
}
}
for ($i=0; $i < $count; $i++) {
for ($j=$i; $j < $count; $j++) {
for ($k=$j; $k < $count; $k++) {
for ($l=$k; $l < $count; $l++) {
for ($m=$l; $m < $count; $m++) {
for ($n=$m; $n < $count; $n++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l] . $numbers[$m] . $numbers[$n];
}
}
}
}
}
}
for ($i=0; $i < $count; $i++) {
for ($j=$i; $j < $count; $j++) {
for ($k=$j; $k < $count; $k++) {
for ($l=$k; $l < $count; $l++) {
for ($m=$l; $m < $count; $m++) {
for ($n=$m; $n < $count; $n++) {
for ($o=$n; $o < $count; $o++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l] . $numbers[$m] . $numbers[$n] . $numbers[$o];
}
}
}
}
}
}
}
echo "<pre>";
print_r($subset);
echo "</pre>";
?>
When I run this code I get the combinations like I wanted (I make the combinations as string to see the results clearly but normally every result item in $subset array must be array)
With this code I can get all unique combinations.
But as you can see this code is ugly. I tried to make this a recursive function but I failed. Could anyone point me to right direction to get the exact same results like this? (every item in $subset array normally must be an array that contains digits)

You can simplify this logic (and make the code less ugly) without needing to go recursive by using:
for ($i = 0; $i < $count; $i++) {
$subset[] = $numbers[$i];
for ($j=$i; $j < $count; $j++) {
$subset[] = $numbers[$i] . $numbers[$j];
for ($k=$j; $k < $count; $k++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k];
for ($l=$k; $l < $count; $l++) {
$subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l];
}
}
}
}

the following will work in all cases even if you have duplicate numbers in your array
$array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14);
sort($array); //in case it 's not sorted
$array = array_slice($array,-7);
$num = count($array );
$total = pow(2, $num);
$result= array();
$element='';
for ($i = 0; $i < $total; $i++)
{
for ($j = 0; $j < $num; $j++)
{
if (pow(2, $j) & $i)
{
$element=$element.$array [$j];
}
}
$result[]=$element;
$element='';
}
print_r($result);

This implementation returns all the combinations of all items (77 = 823542 combinations of 7 items):
function combine_all(array $numbers) {
$count = count($numbers);
$result = array_map('strval', $numbers);
for($i = 1; $i < $count; ++$i) {
$combinations = array_slice($result, pow($count, $i-1));
foreach($numbers as $number) {
foreach($combinations as $combination) {
$result[] = $number . ',' . $combination;
}
}
}
return $result;
}
When using print_r to output the data, it can perform very slowly:
$array = array_fill(0, pow(7,7), '');
$t = microtime(true);
echo '<pre>';
print_r($array);
echo '</pre>';
echo microtime(true) - $t;
// 0.75329303741455
$t = microtime(true);
echo '<pre>';
print_r( combine_all(array(1,2,3,4,5,6,7)) );
echo '</pre>';
echo microtime(true) - $t;
// 1.7037351131439
$t = microtime(true);
combine_all(array(1,2,3,4,5,6,7));
echo microtime(true) - $t;
//0.75869607925415
To restrict the items number, use the array_slice function:
combine_all(array_slice($numbers, 0, 7));
If you really want a recursive function, you could do something like this:
function combine_all(array $numbers, $cnt=null, $baseCombination=null) {
if( $baseCombination === null ) {
$cnt = count($numbers);
}
if( $cnt > 0 ) {
$result = array();
foreach($numbers as $number) {
$combination = $number . ',' . $baseCombination;
$result[] = $combination;
$result = array_merge($result, combine_all($numbers, $cnt-1, $combination));
}
return $result;
}
return array();
}
But it takes too much memory.

I finally found out a way to add recursive function to create unique combinations from given numbers:
$numbers = [1, 2, 3, 4, 5, 6, 7];
function subsetSumRecursive($numbers, $arraySize, $level = 1, $i = 0, $addThis = [])
{
// If this is the last layer, use a different method to pass the number.
if ($level == $arraySize) {
$result = [];
for (; $i < count($numbers); $i++) {
$result[] = array_merge($addThis, array($numbers[$i]));
}
return $result;
}
$result = [];
$nextLevel = $level + 1;
for (; $i < count($numbers); $i++) {
// Add the data given from upper level to current iterated number and pass
// the new data to a deeper level.
$newAdd = array_merge($addThis, array($numbers[$i]));
$temp = subsetSumRecursive($numbers, $arraySize, $nextLevel, $i, $newAdd);
$result = array_merge($result, $temp);
}
return $result;
}
echo "<pre>";
print_r(subsetSumRecursive($numbers, 7));
echo "</pre>";

Related

How can received and clear an array in PHP

I'm trying to look for a number with maximum divisors in a range of 1 - 10000.
I succeeded, but then I wish to verify if there exist more than two max divisors and print them out. My array is really the problem. How can I clear an array and assign a new integer to it in an if else if statement?
Here is what I have tried:
function countDivisors(){
$input = 10000;
$maxNumOfDiv = -1;
$intWMaxDivs = -1;
$curNumOfDiv = 0;
$arr = array();
for($i=1; $i <= $input; $i++) {
$curNumOfDiv = 0;
for ($j = 1; $j < $i; $j++){
if ($i % $j == 0)
$curNumOfDiv++;
}
if($curNumOfDiv = $maxNumOfDiv){
$arr[] = $i;
$intWMaxDivs = $i;
$maxNumOfDiv = $curNumOfDiv;
} else if($curNumOfDiv > $maxNumOfDiv){
$arr = array();
$arr[] = $intWMaxDivs
$maxNumOfDiv = $curNumOfDiv;
}
}
for ($i; $i < count($arr); $i++){
echo $arr[$i]['intWMaxDivs'];
echo $arr[$i]['maxNumOfDiv'];
}
$div = [];
$maxDivKey = false;
$maxDiv = 0;
for($i = 1; $i <= 10000; $i++) {
for ($j = 1; $j < $i; $j++){
if ($i % $j == 0){
$div[$i][] = $i.'/'.$j.'='.$i/$j;
}
if($j == $i-1){
$count = count($div[$i]);
$div[$i]['count'] = $count;
if($maxDiv < $count){
$maxDiv = $count;
$maxDivKey = $i;
}
}
}
}
echo '<h1>Max divisors:</h1>';
print_r($div[$maxDivKey]);
//print_r($div);
I may be misunderstanding this question a little. If you are looking for a single number with maximum number of dividers, it should be something like this.
<?php
$max_num=10000;
$start_num=1;
$max_divs=-1;
$max_number=-1;
$numbers=array();
$max_divs_arr=array();
for($i=$start_num;$i<=$max_num;$i++)
{
$divs=0;
$div_array=array();
for($j=$start_num;$j<=$i;$j++)
{
if($i%$j==0)
{
$divs++;
$div_array[]=$j;
}
}
if($divs==$max_divs)
$max_divs_arr[$i]=$div_array;
if($divs>$max_divs)
{
$max_divs_arr=array();
$max_divs=$divs;
$max_divs_arr[$i]=$div_array;
}
}
foreach($max_divs_arr as $number=>$divisors)
echo "\nNumber with most divisors is $number\nIt has $max_divs divisors\nThose divisors are:".implode(',',$divisors);

for loop gets executed just once

I have created an array dynamically like this way
$names = array();
for ($i = 0; $i < 100; $i++) {
$names[] = $i;
}
then created part
$parts = count($names) / 20;
and created a sub array then loop through the parts
$j = 0;
for ($i = 0; $i < $parts; $i++) {
echo "Part" . $i."<br>";
$newarray = array_slice($names, $j, 20);
for ($i = 0; $i < count($newarray); $i++) {
echo $i;
}
$j = $j + 20;
}
The problem is that this code displays from zero to 19 It doesn't display the other parts
Both the inner and outer loops use the same control variable $i, so just change the inner one...
$j = 0;
for ($i = 0; $i < $parts; $i++) {
echo "Part" . $i."<br>";
$newarray = array_slice($names, $j, 20);
for ($i1 = 0; $i1 < count($newarray); $i1++) {
echo $i1;
}
$j = $j + 20;
}

how to write a nested php loop that draws an image with few lines of code?

How best can i solve this with less code as possible below is the problem
*****
****x
***xx
**xxx
*****
**xxx
***xx
****x
*****
this is my code that i want to improve:
<?php
for ($i=0; $i < 5 ; $i++) {
if($i >= 1 & ($i <= 3))
{
for ($t=0; $t < 5-$i ; $t++)
echo "*";
for ($t=0; $t < $i ; $t++)
echo "x";
}
else
for ($j=0; $j < 5 ; $j++)
echo "*";
echo "<br/>";
}
for ($f=1; $f < 5 ; $f++) {
for ($j=0; $j < $f+1; $j++)
echo "*";
for ($v=3; $v>= $f; $v--)
echo "x";
echo "<br/>";
}
?>
To create string with repeated symbols you can use str_repeat. Using this function your code can be simplified to:
$num = 5;
for ($i = $num; $i > 1; $i--) {
echo str_repeat('*', $i) . str_repeat('x', $num - $i) . PHP_EOL;
}
echo str_repeat('*', $num) . PHP_EOL;
for ($i = 2; $i <= $num; $i++) {
echo str_repeat('*', $i) . str_repeat('x', $num - $i) . PHP_EOL;
}
Even if you cannot use php core functions, you can write you own function to create same results as str_repeat:
function createLine($starsCount, $XCount) {
$result = '';
for ($i = 0; $i < $starsCount; $i++) {
$result .= '*';
}
for ($i = 0; $i < $XCount; $i++) {
$result .= 'x';
}
return $result;
}
And rewrite code as:
$num = 5;
for ($i = $num; $i > 1; $i--) {
echo createLine($i, $num - $i) . PHP_EOL;
}
echo createLine($num, 0) . PHP_EOL;
for ($i = 2; $i <= $num; $i++) {
echo createLine($i, $num - $i) . PHP_EOL;
}

How to count how many duplicates an array has in Php

I'm new to Php and today I came across the rand()-function. I'd like to fill an array with numbers created with this function and then count the number of its duplicates. I already tried it a first time, but somehow I seem to be on the woodway.
<?php
$numbers = array();
for ($i=0; $i < 100; $i++) {
$numbers[$i] = rand(0, 100);
}
//$numbers = array(12,12,12,12);
echo "random numbers generated.<br>";
$arrLength = count($numbers);
$arrWithDoubles = array();
for ($i=0; $i < $arrLength; $i++) {
//echo "start looping for i: ".$i."! numbers['i'] has the content".$numbers[$i].".<br>";
for ($x=$i; $x < $arrLength; $x++) {
//echo "looped for x: ".$x."! numbers['x'] has the content".$numbers[$x].".<br>";
if($numbers[$i] == $numbers[$x]) {
if($i != $x) {
//echo "pushed to 'arrWithDoubles'.<br>";
array_push($arrWithDoubles, $numbers[$x]);
}
}
}
}
echo "numbers of doubles: ".count($arrWithDoubles)."<br>";
echo "list of numbers which were double:<br>";
for ($i=0; $i < count($arrWithDoubles); $i++) {
echo $arrWithDoubles[$i];
echo "<br>";
}
?>
The array_unique() function removes duplicates from an array, then just add a bit of math.
<?php
$numberOfDuplicates = count($orginalArray) - (count($orginalArray) - count(array_unique($originalArray)));
?>
$origin = array(2,4,5,4,6,2);
$count_origin = count($origin);
$unique = array_unique($origin);
$count_unique = count($unique);
$duplicates = $count_origin - $count_unique;
echo $duplicates;
$count = array();
foreach ($srcRandom as $sr) {
if (!array_key_exists ($sr, $count) ) {
$count[$sr] = 1;
continue;
}
$count[$sr]++;
}
var_dump ($count);
Thanks for all your input. With that I came to the following solution which fits my demand the best:
<?php
function countValueInArray($value, $array) {
$count = 0;
for ($i=0; $i < count($array); $i++) {
if($value == $array[$i]) {
$count++;
}
}
return $count;
}
$numbers = array();
for ($i=0; $i < 100; $i++) {
$numbers[$i] = rand(0, 100);
}
$duplicates = array();
for ($x=0; $x < count($numbers); $x++) {
$number = countValueInArray($numbers[$x], $numbers);
if ($number > 1) {
array_push($duplicates, $numbers[$x]);
}
}
$duplicatesList = array_values(array_unique($duplicates));
echo "number of duplicates: ".count($duplicatesList);
echo "<br>these are: <br>";
print_r($duplicatesList);
?>
Thanks a lot for your help!

Bubble sort implementation in PHP? [duplicate]

This question already has answers here:
How can I sort arrays and data in PHP?
(14 answers)
Closed 7 years ago.
I need to do a bubble sort algorithm in PHP.
I want to know whether any one has any good examples that I can use, or an open source library which can do this.
I have a few spaces in a set (array), i want to fill these spaces with object (a person), so no space can have a male and a female, this why i am trying to find out a bubble sort algorithm.
My plan is to fill in any of the available spaces regardless of the gender, and after that sort them separately.
Thanks.
function bubble_sort($arr) {
$size = count($arr)-1;
for ($i=0; $i<$size; $i++) {
for ($j=0; $j<$size-$i; $j++) {
$k = $j+1;
if ($arr[$k] < $arr[$j]) {
// Swap elements at indices: $j, $k
list($arr[$j], $arr[$k]) = array($arr[$k], $arr[$j]);
}
}
}
return $arr;
}
For example:
$arr = array(1,3,2,8,5,7,4,0);
print("Before sorting");
print_r($arr);
$arr = bubble_sort($arr);
print("After sorting by using bubble sort");
print_r($arr);
Using bubble sort is a very bad idea. It has complexity of O(n^2).
You should use php usort, which is actually a merge sort implementation and guaranteed O(n*log(n)) complexity.
A sample code from the PHP Manual -
function cmp( $a, $b ) {
if( $a->weight == $b->weight ){ return 0 ; }
return ($a->weight < $b->weight) ? -1 : 1;
}
usort($unsortedObjectArray,'cmp');
$numbers = array(1,3,2,5,2);
$array_size = count($numbers);
echo "Numbers before sort: ";
for ( $i = 0; $i < $array_size; $i++ )
echo $numbers[$i];
echo "n";
for ( $i = 0; $i < $array_size; $i++ )
{
for ($j = 0; $j < $array_size; $j++ )
{
if ($numbers[$i] < $numbers[$j])
{
$temp = $numbers[$i];
$numbers[$i] = $numbers[$j];
$numbers[$j] = $temp;
}
}
}
echo "Numbers after sort: ";
for( $i = 0; $i < $array_size; $i++ )
echo $numbers[$i];
echo "n";
function bubble_sort($arr) {
$n = count($arr);
do {
$swapped = false;
for ($i = 0; $i < $n - 1; $i++) {
// swap when out of order
if ($arr[$i] > $arr[$i + 1]) {
$temp = $arr[$i];
$arr[$i] = $arr[$i + 1];
$arr[$i + 1] = $temp;
$swapped = true;
}
}
$n--;
}
while ($swapped);
return $arr;
}
function bubbleSort(array $arr)
{
$n = sizeof($arr);
for ($i = 1; $i < $n; $i++) {
for ($j = $n - 1; $j >= $i; $j--) {
if($arr[$j-1] > $arr[$j]) {
$tmp = $arr[$j - 1];
$arr[$j - 1] = $arr[$j];
$arr[$j] = $tmp;
}
}
}
return $arr;
}
// Example:
$arr = array(255,1,22,3,45,5);
$result = bubbleSort($arr);
print_r($result);
//====================================================
//------- improved version----------------------------
//====================================================
function bubbleSortImproved(array $arr)
{
$n = sizeof($arr);
for ($i = 1; $i < $n; $i++) {
$flag = false;
for ($j = $n - 1; $j >= $i; $j--) {
if($arr[$j-1] > $arr[$j]) {
$tmp = $arr[$j - 1];
$arr[$j - 1] = $arr[$j];
$arr[$j] = $tmp;
$flag = true;
}
}
if (!$flag) {
break;
}
}
return $arr;
}
// Example:
$arr = array(255,1,22,3,45,5);
$result = bubbleSortImproved($arr);
print_r($result);
Improved Bubble Sorting enjoy :)
$sortarr = array(3,5,15,3,2,6,7,50,1,4,5,2,100,9,3,2,6,7,13,18);
echo "<pre>";
// Array to be sorted
print_r($sortarr);
// Sorted Array
print_r(bubble_sort($sortarr));
echo "<pre>";
function bubble_sort($sortarr){
// Bubble sorting
$array_count = count($sortarr);
for($x = 0; $x < $array_count; $x++){
for($a = 0 ; $a < $array_count - 1 ; $a++){
if($a < $array_count ){
if($sortarr[$a] > $sortarr[$a + 1] ){
swap($sortarr, $a, $a+1);
}
}
}
}
return $sortarr;
}
function swap(&$arr, $a, $b) {
$tmp = $arr[$a];
$arr[$a] = $arr[$b];
$arr[$b] = $tmp;
}
Maybe someone finds useful my version of Bubble Sort:
function BubbleSort(&$L)
{
$rm_key = count($L);
while( --$rm_key > -1 )#after this the very first time it will point to the last element
for($i=0; $i<$rm_key; $i++)
if( $L[$i] > $L[$i+1] )
list($L[$i],$L[$i+1]) = array($L[$i+1],$L[$i]);
}
I got the swap idea (using list) from above comment.

Categories