Php getting all combinations for a n dimensional array - php

I have an array of route elements (point1, point2, ...) to provide to a map engine.
I don't know how many points I have. Each point is an array of possible addresses.
I need to perform a check for every combination possible of these points, but only one successful check is required.
My array looks like something akin to:
$point[0] = array($address1, $address2, $adress3);
$point[1] = array($address1, $address2);
$point[2] = array($address1, $address2, $adress3, $adress4);
$point[n] = ...
I want to perform a test for combination: $point[0][0] - $point[1][0] - $point[2][0], $point[0][1] - $point[1][0] - $point[2][0], and so on ! :)
The first successful test (route found) should end the function.
I'm trying to do something with recursion but have spent many hours on this without success.

If I got you right, you want to have a "cartesian product".
This is an example function for it:
It first checks, if there are any subvalues in one of the subarrays and then it creates an array with all possible arraycombinations and returns it.
<?php
function array_cartesian_product($arrays)
{
$result = array();
$arrays = array_values($arrays);
$sizeIn = sizeof($arrays);
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array)
$size = $size * sizeof($array);
for ($i = 0; $i < $size; $i ++)
{
$result[$i] = array();
for ($j = 0; $j < $sizeIn; $j ++)
array_push($result[$i], current($arrays[$j]));
for ($j = ($sizeIn -1); $j >= 0; $j --)
{
if (next($arrays[$j]))
break;
elseif (isset ($arrays[$j]))
reset($arrays[$j]);
}
}
return $result;
}
?>

Related

Combining and Permuting items of two different arrays in PHP

How do I return all possible combinations [12345], [12354] up to [54312], [54321] without having to run 120 for...loop as in the case of combining a 2-item array in the code below?
To return all possible combinations from the given array $word = [1,2],
//break the array into 2 separate arrays
$arr1 = $word[0]; $arr2 = $word[1];
//computer for first array item...each item will have 2 loops
for($i=0; $i<count($arr1); $i++){
for($j=0; $j<count($arr2); $j++){
$ret = $arr1[$i] . $arr2[$j]; array_push($result, $ret);
}
}
//computer for second array item..each item will have 2 loops
for($i=0; $i<count($arr2); $i++){
for($j=0; $j<count($arr1); $j++){
$ret = $arr2[$i] . $arr1[$j]; array_push($result, $ret);
}
}
//display the result
for ($i = 0; $i < count($result); $i++){
echo result([$i];
}
The above code works well.
But for a 5-item array [1,2,3,4,5], it will require about (5 items * 24 loops) = 120 loops.
As seen, you wanted to split 2 strings into chars and obtain all combination by 2 chars: first form blank1 and second from blank2.
Instead of doing the combination manually use a regular for-loop.
$result = array();
for ($i = 0; $i < count($blank1); $i++)
{
for ($j = 0; $j < count($blank2); $j++)
{
//set combination
$aux = $blank1[$i].$blank2[$j];
array_push($result, $aux);
}
}
//result should be populated with combination of 2
//just list it and use as need
for ($i = 0; $i < count($result); $i++)
{
echo $result[$i];
}
//same with stored or checking on db : use loops
For multiple combination, use more nested loops
eg: [blank1][blank2][blank1] - 3 combination
$result = array();
//1
for ($i = 0; $i < count($blank1); $i++)
{
//2
for ($j = 0; $j < count($blank2); $j++)
{
//3
for ($k = 0; $k < count($blank1); $k++)
{
//set combination
$aux = $blank1[$i].$blank2[$j].$blank1[$k];
array_push($result, $aux);
}
}
}
Same as any number you wanted ! It will be a little annoying if have to write many loops but note while can be used with an adequate algorithm. But for the moment just keep as simple as you can and get the desired result.

Multiple comparisons inside for loops don't break php code. Why?

Why this piece of code works when it is clearly wrong in the second for loop (for ($i==0; $i<$parts; $i++) {)?
Does php allows for multiple comparisons inside for loops?
function split_integer ($num,$parts) {
$value = 0;
$i = 0;
$result = [];
$modulus = $num%$parts;
if ($modulus == 0) {
for($i = 0; $i < $parts; $i++)
{
$value = $num/$parts;
$result[] = $value;
}
} else {
$valueMod = $parts - ($num % $parts);
$value = $num/$parts;
for ($i==0; $i<$parts; $i++) {
if ($i >= $valueMod) {
$result[] = floor($value+1);
} else {
$result[] = floor($value);
}
}
}
return $result;
}
Code for ($i==0; $i < $parts; $i++) runs because $i==0 has no impact on loop.
In normal for loop first statement just sets $i or any other counter's initial value. As you already set $i to 0 earlier, your loop runs from $i = 0 until second statement $i < $parts is not true.
Going further, you can even omit first statement:
$i = 0;
for (; $i < 3; $i++) {
echo $i;
}
And loop will still run 3 times from 0 to 2.

Calculate from an array the number that is equal or higher and closest to a given number

I need to calculate from a given array the number that is equal or higher and closest to a given number in PHP. Example:
Number to fetch:
6.85505196
Array to calculate:
3.11350000
4.38350000
4.04610000
3.99410000
2.86135817
0.50000000
Only correct combination should be:
3.99410000 + 2.86135817 = 6.85545817
Can somebody help me? It's been 3 hours I'm getting mad!
UPDATE: I finally finished my code as following:
$arr = array(3.1135, 4.3835, 4.0461, 3.9941, 2.86135817, 0.5);
$fetch = 6.85505196;
$bestsum = get_fee($arr, $fetch);
print($bestsum);
function get_fee($arr, $fetch) {
$bestsum = 999999999;
$combo = array();
$result = array();
for ($i = 0; $i<count($arr); $i++) {
combinations($arr, $i+1, $combo);
}
foreach ($combo as $idx => $arr) {
$sum = 0;
foreach ($arr as $value) {
$result[$idx] += $value;
}
if ($result[$idx] >= $fetch && $result[$idx] < $bestsum) $bestsum = $result[$idx];
}
return $bestsum;
}
function combinations($arr, $level, &$combo, $curr = array()) {
for($j = 0; $j < count($arr); $j++) {
$new = array_merge($curr, array($arr[$j]));
if($level == 1) {
sort($new);
if (!in_array($new, $combo)) {
$combo[] = $new;
}
} else {
combinations($arr, $level - 1, $combo, $new);
}
}
}
I hope the following example might help you. Please try this
<?php
$array = array(
"3.11350000",
"4.38350000",
"4.04610000",
"3.99410000",
"2.86135817",
"0.50000000"
);
echo "<pre>";
print_r($array);// it will print your array
for($i=0; $i<count($array); $i++)
{
$j=$i+1;
for($j;$j<count($array); $j++)
{
$sum = $array[$i] + $array[$j];
// echo $array[$i]. " + ".$array[$j]." = ".$sum."<br>"; //this will display all the combination of sum
if($sum >= 6.85505196 && ($sum <= round(6.85505196)) )//change the condition according to your requirement
{
echo "The correct combinations are:<br/><br/>";
echo "<b>". $array[$i]. " + ".$array[$j]." = ".$sum."<b>";
echo "<br/>";
}
}
echo "<br/>";
}
?>
We will get the result as below
Array
(
[0] => 3.11350000
[1] => 4.38350000
[2] => 4.04610000
[3] => 3.99410000
[4] => 2.86135817
[5] => 0.50000000
)
The correct combinations are:
4.04610000 + 2.86135817 = 6.90745817
3.99410000 + 2.86135817 = 6.85545817
You should do it in two steps:
a. Work out (or look up) an algorithm to do the job.
b. Implement it.
You don't say what you've managed in the three hours you worked on this, so here's a "brute force" (read: dumb) algorithm that will do the job:
Use a variable that will keep your best sum so far. It can start out as zero:
$bestsum = 0;
Try all single numbers, then all sums of two numbers, then all sums of three numbers, etc.: Every time you find a number that meets your criteria and is better than the current $bestsum, set $bestsum to it. Also set a second variable, $summands, to an array of the numbers you used to get this result. (Otherwise you won't know how you got the solution). Whenever you find an even better solution, update both variables.
When you've tried every number combination, your two variables contain the best solution. Print them out.
That's all. It's guaranteed to work correctly, since it tries all possibilities. There are all sorts of details to fill in, but you can get to work and ask here for help with specific tasks if you get stuck.
Thank you all for your help!
My code is working pretty cool when is needed to fetch one or two numbers (addition) only. But can't figure out how to add more combinations up to the total count of elements in my given array.
I mean if there are, let's say, 8 numbers in my array I want to try all possible combinations (additions to each other) as well.
My actual code is:
$bestsum = 1000000;
for ($i = 0; $i < count($txinfo["vout"]); $i++) {
if ($txinfo["vout"][$i]["value"] >= $spent && $txinfo["vout"][$i]["value"] < $bestsum) {
$bestsum = $txinfo["vout"][$i]["value"];
}
}
for($i = 0; $i < count($txinfo["vout"]); $i++) {
$j = $i + 1;
for($j; $j < count($txinfo["vout"]); $j++) {
$sum = $txinfo["vout"][$i]["value"] + $txinfo["vout"][$j]["value"];
if($sum >= $spent && $sum < $bestsum) {
$bestsum = $sum;
}
}
}
$fee = bcsub($bestsum, $spent, 8);
print("Fee: ".$fee);
New updated code.
<?php
$x = 6.85505196;
$num = array(3.1135, 4.3835, 4.0461, 3.9941, 2.86135817, 0.5);
asort($num); //sort the array
$low = $num[0]; // lowest value in the array
$maxpossible = $x+$low; // this is the maximum possible answer, as we require the number that is equal or higher and closest to a given number
$num = array_values($num);
$iterations = $x/$num[0]; // possible combinations loop, to equate to the sum of the given number using the lowest number
$sum=$num;
$newsum = $sum;
$k=count($num);
for($j=0; $j<=$iterations; $j++){
$l = count($sum);
for($i=0; $i<$l; $i++){
$genSum = $sum[$j]+$sum[$i];
if($genSum <= $maxpossible){
$newsum[$k] = $genSum;
$k++;
}
}
$newsum = array_unique($newsum);
$newsum = array_values($newsum);
$k = count($newsum);
$sum = $newsum;
}
asort($newsum);
$newsum = array_values($newsum);
for($i=0; $i<count($newsum); $i++){
if($x<=$newsum[$i]){
echo "\nMaximum Possible Number = ".$newsum[$i];
break;
}
}
?>

Get first value of array and store in new array php

I am trying to make card game.
I have 6 variable that are stored in array. Than I use fisherYates method to randomize array, and display four of them.
Problem is, when I randomize it this way only, it will give only random output of those six, with all different types.
So I want that some repeats like, if you draw four cards, you get output of
ex: club, club, diamond,heart, or heart, star,star,heart.. if you get a point..
I thought to do it like this way: put the array in loop of 4 times, and every time it loops, it stores first, or last value in new array, so that way, I can have greater chances of combination of same cards in output array.
But I'm stuck, and I don't know how to do it :/
this is what I've tried so far
$diamond = 'cube.jpg';
$heart = 'heart.jpg';
$spade = 'spade.jpg';
$club = 'tref.jpg';
$star='star.jpg';
$qmark='qmark.jpg';
$time=microtime(35);
$arr=[$diamond,$heart,$spade,$club,$star,$qmark];
function fisherYatesShuffle(&$items, $time)
{
for ($i = count($items) - 1; $i > 0; $i--)
{
$j = #mt_rand(0, $i);
$tmp = $items[$i];
$items[$i] = $items[$j];
$items[$j] = $tmp;
}
return $items;
}
$i=0;
do {
$niz[$i]=fisherYatesShuffle($arr,$time);
reset($niz);
$i++;
} while ($i <= 3);
Got a solution. Was just to simply do foreach of first element of multidimensional array :)
Code goes like this:
$diamond = 'cube.jpg';
$heart = 'heart.jpg';
$spade = 'spade.jpg';
$club = 'tref.jpg';
$star='star.jpg';
$qmark='qmark.jpg';
$time=microtime(35);
$arr=[$diamond,$heart,$spade,$club,$star,$qmark];
$niz=array();
$i=0;
do {
$niz[$i]=fisherYatesShuffle($arr,$time);
//reset($niz);
$i++;
} while ($i <= 3);
foreach ($niz as $key ) {
$randomArr[]=$key[0]; ;
}
function fisherYatesShuffle(&$items, $time)
{
for ($i = count($items) - 1; $i > 0; $i--)
{
$j = #mt_rand(0, $i);
$tmp = $items[$i];
$items[$i] = $items[$j];
$items[$j] = $tmp;
}
return $items;
}
print_r($randomArr);

PHP array_push adding null instead of integer

I have an array output. It should have a set of tuples within it. I create those tuples on the run from the for loop. (Simplified version of my code - the logic is the same, but $ind is calculated in a more complex way)
$output = Array();
$length = count($data);
for ($i = 0; $i < $length; $i++) {
$ind = $i - ($i % 2);
array_push($output[$ind], $data[$i]);
}
Here is the sample input ($data):
[10,2,123,4,34,6]
And a sample output ($output):
[[10,2],[123,4,],[34,6]]
But I get (not even empty arrays):
[,,] == [null,null,null]
$data[$i] is an integer. I tries to explicitly call intval() on it - still no luck. Also *array_push()* does not return anything after execution. No errors or warnings thrown..
From PHP documentation (http://php.net/manual/en/function.array-push.php):
Note: array_push() will raise a warning if the first argument is not an array. This differs from the $var[] behaviour where a new array is created.
The array was not initialized when the push was called.
Use $output[$ind][] = $data[$i];
Turn on error reporting while developing (I suggest to set it to E_ALL), you'll see all the problems.
You're trying to push values to non existing array - you have to check if array has been already created at index you want to push and create it if it does not exists. Additional problem in your code is that you're doing one loop too much (should be $i < $length) :
$output = Array();
$length = count($data);
for ($i = 0; $i < $length; $i++) {
$ind = $i - ($i % 2);
if (!isset($output[$ind])) $output[$ind] = array();
array_push($output[$ind], $data[$i]);
}
$output array is not initialized when using array_push(), try this
$data = array(10,2,123,4,34,6);
$output = Array();
$length = count($data);
for ($i = 0; $i < $length; $i++) {
$ind = $i - ($i % 2);
//array_push($output[$ind], $data[$i]);
$output[$ind] = $data[$i];
}
var_dump(array_values($output));
Output
array(3) {
[0] => int(2)
[1] => int(4)
[2] => int(6)
}
An easier way to accomplish the same thing:
$output = array_chunk($data, 2);

Categories