1

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);
        }
    }
}
supermoney
  • 79
  • 2
  • 6
  • 2
    Would you please post the code you've tried so far. A MCVE would improve your question (without some of you own code, it looks like you want us to code for you). – Richard Erickson Jan 13 '16 at 02:19
  • Why only 3.99410000 + 2.86135817 = 6.85545817 is correct. I see "that is equal or higher to a given number", so array above have a lot of suitable combination. – vien vu Jan 13 '16 at 02:19
  • Because 6.85545817 is the closest combination since there are higher combinations which may be ok but I need the closest one. Actually I could code the single closest number but it's still far from my needs. – supermoney Jan 13 '16 at 02:22
  • What do you want back. The two numbers? The indexes to the two numbers? The written formula the way you presented it? – random_user_name Jan 13 '16 at 02:38

4 Answers4

3

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
Sujan Shrestha
  • 612
  • 3
  • 13
  • 34
  • Thank you I've updated and added above my code with your scheme and it's perfectly working with a combination of two numbers, but can't figure out how to calculate more numbers if my array have more than 2 numbers. Example: array of 10 numbers and correct combination is composed by 4 numbers and so on. – supermoney Jan 13 '16 at 17:34
2

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:

  1. Use a variable that will keep your best sum so far. It can start out as zero:

    $bestsum = 0;
    
  2. 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.

  3. 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.

alexis
  • 48,685
  • 16
  • 101
  • 161
  • I've added my actual updated code, just it misses the part where doing more than 2 combinations. I suppose I've to do a multiple foreach but not sure, can you give it a look? Thanks. – supermoney Jan 13 '16 at 17:32
0

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

?>
sandyclone
  • 149
  • 4
  • Thank for the help but I recently finished it. You can see my code on top. – supermoney Jan 14 '16 at 13:57
  • Your script si faster than mine but sometimes is not working. Example: x = 506 and array is 507, 8, 1. The problem is caused by "1", why? – supermoney Jan 14 '16 at 14:58
  • What on earth does this do? Why is `$iterations` set to this value? What is `$maxpossible` for? I don't understand why the OP accepted it: It's impossible to verify that the code works correctly when it's not clear what it's meant to do. Please add an explanation of the algorithm. – alexis Jan 15 '16 at 14:22
  • It wasn't my intention to click on "accept" button, I just wanted to press on "useful" button but pressed on the wrong button, sorry! However, I'm still using my own code but once I use more than 7+ inputs it doesn't finish the loop and can't get the correct number. Any ideas? – supermoney Jan 15 '16 at 19:36
  • Most likely there are just too many possibilities; it's called "combinatorial explosion". "Optimizing" your code to shave off a few cycles is no help; it might run faster, but will grow just as much with larger input sizes. The only way around it is to look up a smarter algorithm. – alexis Jan 15 '16 at 22:19
  • I have updated the code. Explained what maxpossible is for and the iterations. This also works when the array also contains 1 – sandyclone Jan 16 '16 at 01:41
0

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);
supermoney
  • 79
  • 2
  • 6
  • Don't add extra loops; after all, you don't know how long your array is so you don't know how many loops you'd need (and writing, say, 8 nested loops is a terrible solution). Treat it as a separate problem, and write a separate function to solve it: How do you get [all subsets](http://stackoverflow.com/a/6092999/699305) of an array of numbers? And how do you get the sum of all numbers in a subset? – alexis Jan 13 '16 at 18:20
  • But please don't use an answer to give more information about your question-- it's against the rules of the site. Edit your question to add more information (but avoid the temptation to put the entire answer in the question). – alexis Jan 13 '16 at 18:23
  • I apologize but I'm not familiar to this site and its rules. Anyways I found out the solution here -> [Find all possible unique combinations of elements of an array in PHP](http://stackoverflow.com/questions/15624662/find-all-possible-unique-combinations-of-elements-of-an-array-in-php) – supermoney Jan 13 '16 at 20:07
  • No prob, we all have to learn the rules. And once you have resolved your question, please "accept" the answer that helped you the most by clicking on the big check mark next to it. – alexis Jan 13 '16 at 20:14