Saturday, October 10, 2009

Update: PHP eval is powerful indeed

I came up with a solution though not very elegant one to the options dependent looping, by using eval() function once more. Took time to came up with the solution, especially it's not very easy to debug, except for outputting the code to the screen before executing eval().
"Person A", "PROJECT"=>1, "COUNTRY"=>1, "HOURS"=>40),
  array("NAME"=>"Person A", "PROJECT"=>1, "COUNTRY"=>1, "HOURS"=>30),
  array("NAME"=>"Person A", "PROJECT"=>1, "COUNTRY"=>2, "HOURS"=>70),
  array("NAME"=>"Person A", "PROJECT"=>2, "COUNTRY"=>2, "HOURS"=>10),
  array("NAME"=>"Person A", "PROJECT"=>3, "COUNTRY"=>1, "HOURS"=>50),
  array("NAME"=>"Person B", "PROJECT"=>1, "COUNTRY"=>2, "HOURS"=>40),
  array("NAME"=>"Person B", "PROJECT"=>1, "COUNTRY"=>2, "HOURS"=>10),
  array("NAME"=>"Person B", "PROJECT"=>2, "COUNTRY"=>2, "HOURS"=>50),
  );
$expecteddata1 = array(
  array("NAME"=>"Person A", "HOURS"=>200),
  array("NAME"=>"Person B", "HOURS"=>100),
);
$expecteddata2 = array(
  array("NAME"=>"Person A", "PROJECT"=>1, "HOURS"=>140),
  array("NAME"=>"Person A", "PROJECT"=>2, "HOURS"=>10),
  array("NAME"=>"Person A", "PROJECT"=>3, "HOURS"=>50),
  array("NAME"=>"Person B", "PROJECT"=>1, "HOURS"=>50),
  array("NAME"=>"Person B", "PROJECT"=>2, "HOURS"=>50),
);

function groupData($input, $byOptions) {
  $str = "";
  foreach($byOptions as $option) {
    $str .= '[$row['.$option.']]';
  }
  $data = array();
  foreach($input as $rowid=>$row) {
    eval("@\$data".$str."['hours'] += ".$row['HOURS'].";");
  }
  
  $newdata = array();
  
  $str = ""; 
  $count = 0;
  foreach($byOptions as $option) {
    $str .= '"'.$option.'"=>"$id'.$count.'",';
    $count ++;
  }
  $str='array('.$str.'"HOURS"=>"$hours")';

  $count = 0;
  $forstr = 'foreach($data as $id'.($count).'=>$arr'.($count).') {';
  foreach($byOptions as $option) {
    if($count >= (sizeof($byOptions)-1))  {
      $forstr .= '$hours=$arr'.$count.'["hours"];';
      break;
    }
    $forstr .= 'foreach($arr'.$count.' as $id'.($count+1).'=>$arr'.($count+1).') {';
    $count++;
  }
  $forstr .= '$newdata[]='.$str.';';
  $count = 0;
  foreach($byOptions as $option) {
    if($count >= (sizeof($byOptions)-1))  {
      break;
    }
    $forstr .= '}';
    $count ++;
  }
  $forstr .= '}';
  
  //print $forstr;
  eval("$forstr");
  return $newdata;
}

$output1 = groupData($data, array("NAME"));
print ($expecteddata1 == $output1)?"Same":"Different Objects";

$output2 = groupData($data, array("NAME", "PROJECT"));
print ($expecteddata2== $output2)?"Same":"Different Objects";  
?>

No comments: