0

I have a code which displays the variables which are equal to 0.:

$a = 1;
$b = -1;
$c = 2;

if($a + $b + $c == 0){
 echo "a,b & c \n";   
}

if($a + $b == 0){
 echo "a & b \n";   
}

if($a + $c == 0){
 echo "a & c \n";   
}

if($c + $b == 0){
 echo "c & b \n";   
}

This will result:

a & b

When I change the value:

$a = -1;
$b = 0.5;
$c = 0.5;

This will result:

a,b & c

Is there any clean and easy functional way to code this feature in PHP?

kipago
  • 3
  • 2
  • So if I understand correctly, your code is working fine, you are just asking for how to reformat the code so it looks clean? – catcon Sep 15 '19 at 10:15

2 Answers2

1

If you can change your inputs to an (associative) array, you can make use of array_sum and a function from "Finding the subsets of an array in PHP" (more specific: Walf's answer) to automatically determine the possible combinations:

function power_set($array) {
    $results = [[]];
    foreach ($array as $key => $value) {
        foreach ($results as $combination) {
            $results[] = $combination + [$key => $value];
        }
    }
    // Remove the first empty set
    array_shift($results);
    // Sort descending by amount of elements
    $order = array_map('count', $results);
    uksort($results, function($key_a, $key_b) use ($order) {
        $comp = $order[$key_b] - $order[$key_a];
        if ($comp == 0) {
            $comp = $key_a - $key_b;
        }
        return $comp;
    });
    return array_values($results);
}

function zero_sums($inputs) {
    $subsets = power_set($inputs);
    foreach ($subsets as $subset) {
        if (array_sum($subset) == 0) {
            echo implode(" & ", array_keys($subset)).PHP_EOL;
        }
    }
}

Sample outputs:

zero_sums(["a" => 1, "b" => -1, "c" => 2]);
// Prints "a & b"
zero_sums(["a" => -0.5, "b" => -0.5, "c" => 1]);
// Prints "a & b & c"
zero_sums(["a" => 1, "b" => -1, "c" => 2, "d" => -1]);
// Prints "b & c & d" / "a & b" / "a & d"
zero_sums(["a" => -1, "b" => -1, "c" => 2, "d" => 1, "e" => -1]);
// Prints "a & b & c & d & e" / "a & b & c" / "a & c & e" / "b & c & e" / "a & d" / "b & d" / "d & e"
Marvin
  • 13,325
  • 3
  • 51
  • 57
  • For `zero_sums(["a" => -1, "b" => -1, "c" => 2, "d" => -1]);` why it results: **b & c & d** and not ***a & b & c***? – kipago Sep 15 '19 at 15:23
  • It results in "a & b & c", "a & c & d" and "b & c & d". Because all 3 have a sum of 0. – Marvin Sep 15 '19 at 15:42
  • Ohh, yes I just missed it! – kipago Sep 15 '19 at 15:48
  • For: `zero_sums(["a" => -1, "b" => -1, "c" => 2, "d" => 1, "e" => -1]);` it results as **a & b & c**, **a & d**, **b & d**, **a & c & e**, **b & c & e**, **d & e**, **a & b & c & d & e** – kipago Sep 15 '19 at 16:04
  • Can it be in descending to ascending order, meaning first **a & b & c & d & e** then **a & c & e** and in last **b & d**? – kipago Sep 15 '19 at 16:05
  • Descending by the number of elements? The simplest way would probably be to sort the result of `power_set`. – Marvin Sep 15 '19 at 16:28
  • _If you can change your inputs to an (associative) array_, you mean like this: `zero_sums([1,-1,2]);`? – kipago Sep 18 '19 at 04:49
  • No. Exactly as written in my answer. – Marvin Sep 18 '19 at 08:57
0

You can approach in this way

 $a = ['a' => -1, 'b' => 0.5, 'c' =>0.5];
//Combinations
$c = [
  ['a','b','c'],
  ['a','b'],
  ['a','c'],
  ['b','c']
];
foreach($c as $v){
  $s = array_sum(array_intersect_key($a,array_flip($v)));
  echo !$s ? (implode(' & ',$v)) : '';
}

Working example : https://3v4l.org/H0If0

Rakesh Jakhar
  • 6,380
  • 2
  • 11
  • 20