简体   繁体   中英

PHP Recursively calculate a formula in an array in reverse

I would like te perform a calculation on the following array

$array = [
    "calculation" => [
        "add" => [
            "ceil" => [
                "multiply" => [
                    9.95,
                    "90%"
                ]
            ],
            0.95
        ]
    ]
];

eventually the calculation would traverse into:

1. add(ceil(multiply(9.95, 90%)), 0.95)
2. ceil(multiply(9.95, 90%)) + 0.95
3. ceil(8.955) + 0.95
4. 9 + 0.95
5. 9.95

I've tried recursively looping through the array using array_walk_recursive and custom functions which basically to the same. but the problem is that the add cannot calculate the ceil before it has calculated the multiply .

So how can i recusively in reversed order calculate all the parts of the array?

I'm slowly loosing my mind over this and starting to question if it's even possible.

All ideas are greatly appreciated

Another option, that verify the indexes of the array are valid functions and allows add and multiple with more than 2 values.

function multiply(...$a)
{
    return array_product($a);
}

function add(...$a)
{
    return array_sum($a);
}

function applyCalculation(array $data)
{
  $firstKey = array_keys($data)[0];
  $arguments = [];
  foreach ($data[$firstKey] as $name => $value) {
      // if argument is array with existing function, we pass it recursively
      if (function_exists($name) && is_array($value)) {
          $result = applyCalculation([$name => $value]);
          $result = is_array($result) ? $result : [$result];
          $arguments = array_merge($arguments, $result);
      } elseif (!is_array($value)) {
          // if not array, just append to arguments
          $value = strpos($value, '%') !== false ? str_replace('%','',$value) / 100 : $value;
          $arguments[] = $value;
      } elseif (is_array($value)) {
          // error here, the index is not a valid function
      }
  }

  return $firstKey(...$arguments);
}

echo applyCalculation($array['calculation']);

So it will work for your example:

$data = [
  "calculation" => [
      "add" => [
          "ceil" => [
              "multiply" => [
                  9.95,
                  '90%',
              ]
          ],
          0.95
      ]
    ]
  ];

// will give you 9.95

But it also works for more complex cases::

$array = [
  "calculation" => [
      "add" => [
          "ceil" => [
              "add" => [
                  "multiply" => [
                      9.95,
                      '90%'
                  ],
                  "add" => [
                      1,
                      3
                  ],
              ]
          ],
          0.95,
          3
      ]
  ]
];


// will give you 16.95

Assuming that you have this structure, you may use this code. If you need more than 2 values to be "added" or "multiplied" you may need to use some splat operator or change the logic a little bit:

<?php

$array = [
    "calculation" => [
        "add" => [
            "ceil" => [
                "multiply" => [
                    9.95,
                    "90%"
                ]
            ],
            0.95
        ]
    ]
];

function add($a, $b) {
    return $a + $b;
}

function multiply($a, $b) {
    return $a * $b;
}

function calculation($arr, $operation = null) {
    
    $elements = [];
    
    foreach($arr as $k => $value) {
        if (is_numeric($k)) {
            // change % with valid numeric value
            if(strpos($value, '%')) {
                $value = str_replace('%','',$value) / 100;
            }
            //if there are no operations, append to array to evaluate under the operation
            $elements[] = $value;
        } else {
            //if there are operations, call the function recursively
            $elements[] = calculation($value, $k);
        }
    }

    if ($operation !== null) {
        return call_user_func_array($operation, $elements);
    }
    return $elements[0];
}

echo calculation($array['calculation']);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM