2

I'm trying to build a tool to average values from a multidimensional array in PHP. Array sample:

$t[1][1]=2;
$t[1][2]=3;
$t[2][1]=5;
$t[3]=6;
$t[4][1][1]=9;
$t[4][1][2]=10;
$t[4][2][1]=12;
$t[4][2][2]=13;

Notice, too, that parents have no value (Since they have children). I have this:

function chklevel($s) {
  $l = explode(".",$s);
}

Which gives me the ability to call chklevel as

chklevel("4.2.2")

and have it return 13, but I also want to be able to call

chklevel("4")

and have it return 11 (Which is the average of 4.1.1(9), 4.1.2(10), 4.2.1(12) and 4.2.2(13).

Any thoughts?

3
  • How can you call chklevel(4.2.2) when the parameter is not a string? This will throw an error. Also, the function chklevel doesn't return anything yet, is that intentional? Maybe I just don't get your question good enough. Commented Mar 5, 2011 at 21:16
  • Sorry - corrected. I could have sworn I had the quotes in there. Also, it's more of a pseudocode than true code, as I've got an explode() handling the string for me. Commented Mar 5, 2011 at 21:18
  • make sure you see my update to the answer, I added an array check (your 4.2.2 example was giving me trouble as an array wasn't passed (a value was) so the foreach bombed--but it's fixed now) Commented Mar 5, 2011 at 21:29

2 Answers 2

1

I had to do it in two functions (just because of the recursive nature of the search, but here's my bid:

function mdarray_avg($array, $level = ''){
  if (!is_array($array)) throw new Exception("First argument must be an array");
  if (!is_string($level)) throw new Exception("Second argument must be string");

  $ary = $array;
  $levels = explode('.',$level);
  foreach ($levels as $lvl){
    if (array_key_exists($lvl,$ary))
      $ary = $ary[$lvl];
    else
      throw new Exception("Level {$level} doesn't exist");
  }

  $numbers = _mdarray_avg($ary);
  $sum = array_sum($numbers);
  return ($sum > 0 ? $sum / count($numbers) : 0);
}

function _mdarray_avg($array){
  if (!is_array($array)) return array($array);
  $numbers = array();
  foreach ($array as $element){
    if (is_array($element))
      $numbers = array_merge($numbers,_mdarray_avg($element));
    else
      $numbers[] = $element;
  }
  return $numbers;
}

Use it like so:

echo "Average: ".mdarray_avg($t,'4'); // returns 11, as expected. 

Where $t is the array to search through, and the '4' is the level you're searching (could also be '1', '4.2', etc.

Also, a fun note, exempting the second parameter averages the whole array, in this case I returned 7.5 (avg(2,3,5,6,9,10,12,13))

Sign up to request clarification or add additional context in comments.

1 Comment

@tommyvallier: not a problem. Also added another checksum against an invalid level (instead of silently skipping over a missing array key it will exception out saying the level doesn't exist [previously using 6.4.2 would actually be averaging 4.2. It wouldn't find level 6, would skip over, then continue on to look for 4])
0

Here's my solution:

function chklevel($t) {

  for ($i = 1; $i < func_num_args(); $i++) {
    if (is_array($t) && isset($t[func_get_arg($i)]))
      $t = $t[func_get_arg($i)];
  }

  return GetAvg($t);
}

function GetAvg($arr) {

  if (is_array($arr)) {
    $avg = 0;
    foreach ($arr as $v) {
      $avg += GetAvg($v);
    }
    $avg /= count($arr);

  } else if (is_numeric($arr)) {
    $avg = $arr;
  }

  return $avg;
}

I prefer function call like this: chklevel($t, 4,2,2); but you could easily modify it for strings:

function chklevel($t, $s) {
  $indexes = explode(".", $s);
  for ($i = 0; $i < count($indexes); $i++) {
    if (is_array($t) && isset($t[$indexes[$i]]))
      $t = $t[$indexes[$i]];
  }

  return GetAvg($t);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.