DanielAttard
DanielAttard

Reputation: 3615

PHP Iterate multi-dimensional array

How can I iterate through this multidimensional array and return the count of positive numbers and the count of negative numbers. The answer should be 1 positive and 5 negative. Thanks.

Array
(
[Nov 18, 2011] => Array
    (
        [C] => Array
            (
                [C] => Array
                    (
                        [T] => -1324.388328
                    )
                [S] => Array
                    (
                        [T] => -249.976472
                    )
            )
    )
[Dec 24, 2011] => Array
    (
        [C] => Array
            (
                [C] => Array
                    (
                        [T] => -2523.107928
                    )
                [S] => Array
                    (
                        [T] => 103.533528
                    )
            )
    )
[Dec 27, 2011] => Array
    (
        [C] => Array
            (
                [C] => Array
                    (
                        [T] => -4558.837928
                    )
                [S] => Array
                    (
                        [T] => -1639.376472
                    )
            )
    )
)

Upvotes: 3

Views: 3026

Answers (3)

user569143
user569143

Reputation:

I had some issues with a recursive solution to this since I am also learning [setting the count to zero as shown above will erase your current count on each recursive call, and I haven't solved reference / scope errors when passing counts as function arguments].

Also, I had to modify the notation of your original array definition to get my test working.
A) I assumed your keys were meant to be string literals, not variables or constants. So I added '' wrappers. If they were meant to be variables defined elsewhere, add your '$'..
B) You need to comma-separate your list of elements within a single array, which I added
C) Not technically necessary, but I do not use bracket notation while defining, only when accessing by key after creation. Developer's choice but it helps me determine if I am ( creating or using existing ) array elements when I go back to the code later.
D) Don't forget to include your ';' after defining the data array, array defs are not self-closing like function or conditional code {} structure

Admittedly, this is a slightly less robust solution than recursion, but it gives you full access to every element by key and by value, at which point you can report or manipulate values as needed. The restriction in this method is you need to know how many levels of nesting (and therefore how many foreach loops). The upshot is adding elements to existing array levels will not affect the loop logic.

<?php

  function html_pp ( $text ) // no return
  {
    // echo paragraph to browser
    echo PHP_EOL . '<p>' . Sprintf ( $text ) . '</p>' . PHP_EOL;
  }

  // Data array
  $data = Array
  (
    'Nov 18, 2011' => Array
    (
      'C' => Array
      (
        'C' => Array ( 'T' => -1324.388328 ), // comma
        'S' => Array ( 'T' => -249.976472  )
      )
    ), // comma
    'Dec 24, 2011' => Array
    (
      'C' => Array
      (
        'C' => Array ( 'T' => -2523.107928 ), // comma
        'S' => Array ( 'T' => 103.533528   )
      )
    ), // comma
    'Dec 27, 2011' => Array
    (
      'C' => Array
      (
        'C' => Array ( 'T' => -4558.837928 ), // comma
        'S' => Array ( 'T' => -1639.376472 )
      )  
    )
  ); // end array def

  // Count variables
  $positive = 0;
  $negative = 0;

  html_pp ( 'Data Array :' );

  // Loop using key => value pairs
  foreach ( $data as $i => $date ) // Iterate through date elements
  {
    foreach ( $date as $j => $c ) // Iterate through C elements
    {
      foreach ( $c as $k => $cs ) // Iterate through C/S elements
      {
        foreach ( $cs as $n => $t ) // Iterate though T elements
        {
          // echo current element nesting path and value
          html_pp ( $i . '>' . $j . '>' . $k . '>' . $n . ' = ' . $t );
          // update +- counts
          if ( $t < 0 ) { $negative += 1; }
          else          { $positive += 1; }
        }
      }
    }
  }

  html_pp ( 'Positive : ' . $positive );
  html_pp ( 'Negative : ' . $negative );

?>

Browser output:

Data Array :

Nov 18, 2011>C>C>T = -1324.388328

Nov 18, 2011>C>S>T = -249.976472

Dec 24, 2011>C>C>T = -2523.107928

Dec 24, 2011>C>S>T = 103.533528

Dec 27, 2011>C>C>T = -4558.837928

Dec 27, 2011>C>S>T = -1639.376472

Positive : 1

Negative : 5

Upvotes: 0

Decent Dabbler
Decent Dabbler

Reputation: 22773

You could also use SPL's RecursiveIteratorIterator in combination with RecursiveArrayIterator, with something like this:

$pos = $neg = 0;
foreach( new RecursiveIteratorIterator( new RecursiveArrayIterator( $data ) ) as $item )
{
    if( !is_numeric( $item ) ) continue;

    $item < 0 ? $neg++ : $pos++;
}
var_dump( $pos, $neg );

Where $data represents your multidimensional array. RecursiveIteratorIterator defaults to only iterating, what are called, the leaves (the items that don't have any children). As a safety measure I still have incorporated a test to check whether the item is indeed a numeral value.

Upvotes: 2

Telmo Marques
Telmo Marques

Reputation: 5106

If the objective is to count the positive and negative numbers of a multidimensional array of unknown depth, build a recursive function. If that's not the case, a recursive function will also get the job done.

function countFromMultidimentionalArray($array)
{
    $positiveCount = 0;

    foreach($array as $value)
    {
        if(is_array($value))
        {
            $positiveCount += countFromMultidimentionalArray($value);
        }
        else
        {
            if($value >= 0)
            {
                $positiveCount++;
            }
        }
    }

    return $positiveCount;
}

I didn't test this, and it only counts positive numbers. You can make a similar function that only counts the negative ones or, more interestingly, find a way of doing both in the same function (maybe using an object?). It's only just to give you an ideia, as this seems like homework and I don't want to spoil all the fun :)

EDIT: Given the fact this isn't homework, here's a more elaborate solution, using an array to hold both values.

function countFromMultidimentionalArray($array)
{
    $values = array();
    $values["positive"] = 0;
    $values["negative"] = 0;

    foreach($array as $value)
    {
        if(is_array($value))
        {
            $result += countFromMultidimentionalArray($value);
            $values["positive"] += $result["positive"];
            $values["negative"] += $result["negative"];
        }
        else
        {
            if($value >= 0)
            {
                $values["positive"]++;
            }
            else
            {
                $values["negative"]++;
            }
        }
    }

    return $values;
}

Also didn't test this one. Hope it helps!

Upvotes: 1

Related Questions