php - Recursive(?) algorithm design -


i have requirement allow end users input formula spreadsheet. have array this:

$table = array(     1=>array(             "id"=>1,             "name"=>"regulating",             "quantity"=>"[2]quantity+[3]value",             "value"=>"[2]cost"         ), ...) 

the first level array key same value id key in array.

a tabulated example follows:

id  name        quantity                value 1   regulating  [2]quantity+[3]value    [2]cost 2   kerbs       3                       6 3   bricks      9                       7 4   sausages    [3]cost                 3 5   bamboo      [4]quantity             [7]cost 6   clams       [4]quantity             null 7   hardcore    [3]quantity*0.5         12 8   beetles     [6]quantity*[4]value    [2]value 

the quantity , value keys represent formula reference [id] , either quantity, value or cost.

cost derived multiplying value , quantity.

i using:

preg_match_all("/\[(.*?)\]([a-z]*[a-z]*)/", $string, $matches, preg_set_order); 

which outputs array for[1][quantity]:

array (     [0] => array         (             [0] => [2]quantity             [1] => 2             [2] => quantity         )      [1] => array         (             [0] => [3]value             [1] => 3             [2] => value         )  ) 

iterating through table using similar to: $calcstring = $table[1]['quantity'];`

foreach ($matches $match) {     $calcstring = str_replace($match[0], $table[$match[1]][$match[2]], $calcstring); } 

i can string calculated , using matheval class sum.

for example

[1]quantity = [2]quantity + [3]value [2]quantity = 3 [3]value = 7 // [1]quantity = 3 + 7 = 10  [1]value = [2]cost [2]cost = [2]quantity * [2]value // 3 * 6 = 18 

basically variables in table refer other [id]key in same table.

but here issue

i need resolve references other parts of table (which may or may not formula) fill in blanks. outside comfort zone , appreciate advice (or better functional code) provides enlightenment on how might able achieve this.

thanks

a dangerously easy, , your-situation-specific well-performable solution!

<?php class solver {     private             // final output array             $arr_evaled,             // when cell gains final value, corresponding entry in following array gets marked being done!             $arr_done;      private $solving_iterations_count;      public function solver($array) {         $this->arr_done = array();          foreach($array $k => $arr)             $this->arr_done[$k] = array('quantity' => false, 'value' => false);          // firstly,expand of "[x]cost"s "([x]quantity*[x]value)"s!         $this->arr_evaled = array_map(             function($v){ return preg_replace('#\[(\d*?)\]cost#', '([$1]quantity*[$1]value)', $v); },             $array         );          $this->solving_iterations_count = 0;         $this->solve();     }      private function isdone() {         foreach($this->arr_done $a)             if($a['quantity'] == false || $a['value'] == false)                 return false;         return true;     }     private function iscelldone($id, $fieldname) {         return $this->arr_done[$id][$fieldname];     }     private function markcellasdone($id, $fieldname, $evaluation) {         $this->arr_done[$id][$fieldname] = true;         $this->arr_evaled[$id][$fieldname] = $evaluation;     }     private function isevaluable($str) {         return preg_match('#^[0-9*+-\/\(\)\.]*$#', $str) == 1 || strtolower($str)=='null';     }     private function replace($from, $to) {         foreach($this->arr_evaled &$arr) {             $arr['quantity'] = str_replace($from, $to, $arr['quantity']);             $arr['value'] = str_replace($from, $to, $arr['value']);         }     }      private function solve() {         $issolvable = true; // todo: believe coding part fun!) (e.g: check "reference cycles")         if(!$issolvable) return null;          while( !$this->isdone() )         {             foreach($this->arr_evaled $arr) {                 foreach(['quantity', 'value'] $fieldname) {                     if(!$this->iscelldone($arr['id'], $fieldname)) {                         if($this->isevaluable($arr[$fieldname])) {                             $evaluation = eval("return {$arr[$fieldname]};");                             $this->markcellasdone($arr['id'], $fieldname, $evaluation);                             $this->replace("[{$arr['id']}]$fieldname", "$evaluation");                         }                     }                 }             }             $this->solving_iterations_count++;         }         foreach($this->arr_evaled &$row)             $row['cost'] = $row['quantity'] * $row['value'];         return $this->arr_evaled;     }      public function print_tabulated() {         echo "the count of solving iterations: {$this->solving_iterations_count}<br/><br/>";         echo '<table border="1"><tr><th>id</th><th>name</th><th>quantity</th><th>value</th><th>cost</th></tr>';         foreach($this->arr_evaled $arr)             echo "<tr><td>{$arr['id']}</td><td>{$arr['name']}</td><td>{$arr['quantity']}</td><td>{$arr['value']}</td><td>{$arr['cost']}</td></tr>";         echo '</table>';     } }  // testing $arr = array(     1 => array( 'id' => 1, 'name' => 'regulating', 'quantity' => '[2]quantity+[3]value', 'value' => '[2]cost'  ),     2 => array( 'id' => 2, 'name' => 'kerbs',      'quantity' => '3',                    'value' => '6'        ),     3 => array( 'id' => 3, 'name' => 'bricks',     'quantity' => '9',                    'value' => '7'        ),     4 => array( 'id' => 4, 'name' => 'sausages',   'quantity' => '[3]cost',              'value' => '3'        ),     5 => array( 'id' => 5, 'name' => 'bamboo',     'quantity' => '[4]quantity',          'value' => '[7]cost'  ),     6 => array( 'id' => 6, 'name' => 'clams',      'quantity' => '[4]quantity',          'value' => 'null'     ),     7 => array( 'id' => 7, 'name' => 'hardcore',   'quantity' => '[3]quantity*0.5',      'value' => '12'       ),     8 => array( 'id' => 8, 'name' => 'beetles',    'quantity' => '[6]quantity*[4]value', 'value' => '[2]value' ), ); echo '<pre>'; (new solver($arr))->print_tabulated(); 

here output:

the output of code in http://stackoverflow.com/a/32805259/3709765


Comments