12

As you can see from the following array, there are three elements that appear on Nov 18, and another two elements that appear on Nov 22. Can someone tell me how I can retrieve the counts of 3 and 2 respectively from this array? Basically, I want to end up with a result something like this:

Nov 18, 2011 = 3 items

Nov 22, 2011 = 2 items

Of course, the dates and the number of different dates will vary every time. Here is the array:

[
    [
        ['2011-11-18 00:00:00' => 'C'],
        ['2011-11-18 00:00:00' => 'I'],
        ['2011-11-18 00:00:00' => 'S']
    ],
    [
        ['2011-11-22 00:00:00' => 'C'],
        ['2011-11-22 00:00:00' => 'S']
    ]
]
3
  • Do you care about the values that are in each of the dates? (i.e. C,I,S,C,S) Commented Nov 27, 2011 at 7:59
  • For now I don't, but soon I will so I should probably try and keep track of those values also. Thanks. Commented Nov 27, 2011 at 8:00
  • So you need a 2d array, of dates as keys, and for each date an array of associated values? Commented Nov 27, 2011 at 8:02

10 Answers 10

29

You can use:

count($array, COUNT_RECURSIVE);

Count number of leaves in nested array tree

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

4 Comments

This answer doesn't look helpful/relevant at all.
@mickmackusa This answer is the most up-voted, so I guess it was helpful / relevant. Don't hesitate to try and not have only a look ;)
I've been here long enough to find many answers that are upvoted yet do not answer the asked question. This means that readers don't know how to vote or don't know what they need. This undercooked answer most definitely does not provide the desired result.
There's no explanation to how count with recursive can help with this. here is the result when this code is ran on the question input. It just gives a "12" (which is unexpected). I would really appreciate if @emiliezawadzki would at least explain how this answer helps reaching a solution to the original question (a few words wouldn't hurt).
9

Does this work for what you need?

$dates = array(array(array("2011-11-18 00:00:00" => C), array("2011-11-18 00:00:00" => I),array
("2011-11-18 00:00:00" => S)),
array(array("2011-11-22 00:00:00" => C), array("2011-11-22 00:00:00" => S)));

$date_count = array();  // create an empty array

foreach($dates as $date) {  // go thought the first level
    foreach($date as $d) {  // go through the second level
        $key = array_keys($d);  // get our date
        // here we increment the value at this date
        // php will see it as 0 if it has not yet been initialized
        $date_count[$key[0]]++;
    }
}
    // show what we have
print_r($date_count);

Prints:

Array ( [2011-11-18 00:00:00] => 3 [2011-11-22 00:00:00] => 2 )

Note: this assumes that you will always be getting data as you structured your array and that each date will be formatted the same. If you can't assume each date will be formatted, this would be a simple conversion using the date() function. If you can't assume that you will get data structured exactly like this, the best way to tackle that would probably be through a recursive function.

1 Comment

Great, let me know if you have any questions. The key thing (no pun intended) is that the array stores values with dates as the key and a number as the value. That value gets incremented each time we see that date.
3

the posted answers are correct for your representative example, but i would like to add another solution, that will work regardless how many nested arrays you may create. it iterates the array recursively and counts all items in all sub-arrays.

it returns the total count of items in the array. in the second argument you can specify an array reference which will contain the count per unique key in the (nested) array(s).

example:

<?php
$deeply_nested = array(
                     'a' => 'x',
                     'b' => 'x',
                     'c' => 'x',
                     'd' => array(
                         'a' => 'x',
                         'b' => 'x',
                         'c' => array(
                             'a' => 'x',
                             'b' => 'x'
                         ),
                         'e' => 'x'
                    ) 
                );

function count_nested_array_keys(array &$a, array &$res=array()) {
    $i = 0;
    foreach ($a as $key=>$value) {
        if (is_array($value)) {
             $i += count_nested_array_keys($value, &$res);
        }
        else {
             if (!isset($res[$key]) $res[$key] = 0;

             $res[$key]++;
             $i++;
        }
    }
    return $i;
}

$total_item_count = count_nested_array_keys($deeply_nested, $count_per_key);

echo "total count of items: ", $total_item_count, "\n";
echo "count per key: ", print_r($count_per_key, 1), "\n";

results in:

total count of items: 8
count per key: Array
(
    [a] => 3
    [b] => 3
    [c] => 1
    [e] => 1
)

1 Comment

@Kaii: You might be interested in this way of recursive traversal as well: stackoverflow.com/a/8295478/367456 - see the second code example.
2

Assuming that your array example is representative:

foreach ($array as $key => $value)
{
   echo count($value) . "<br />";
}

Will echo the number of arrays within each of the main array items. In your example, that would also be the number of entries for each date.

This does not of course check the dates themselves

Comments

2

For your specific $array structure I think the most lean way is using foreach and then getting the date value and the count() out of each value:

$dateCounts = array();
foreach($array as $date)
{
    $dateCounts[key($date[0])] = count($date);
}
var_dump($dateCounts);

With your $array this gives:

array(2) {
  ["2011-11-18 00:00:00"]=> int(3)
  ["2011-11-22 00:00:00"]=> int(2)
}

If you're looking for a more general way, you can make use of RecursiveArrayIterator and RecursiveIteratorIterator to traverse over all leaf key/value elements and then just count the keys:

$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
$keyCounts = array();
foreach ($it as $key => $value)
{
    isset($keyCounts[$key]) ? $keyCounts[$key]++ : $keyCounts[$key] = 1; 
} 
var_dump($keyCounts);

Hope this helps.

1 Comment

Another functional style equivalent: 3v4l.org/s7ZUR
1

You can use array_walk_recursive() to get access to all of the leaf nodes in an array structure.

Something akin to this should work for you:

<?php

$data = array(
 array(
  array('2011-11-18 00:00:00' => 'C'),
  array('2011-11-18 00:00:00' => 'I'),
  array('2011-11-18 00:00:00' => 'S')),
 array(
  array('2011-11-22 00:00:00' => 'C'),
  array('2011-11-22 00:00:00' => 'S')));

function countleafkeys($value, $key, $userData)
{
  echo "$key\n";
  if(!isset($userData[$key])) {
    $userData[$key] = 1;
  } else {
    $userData[$key]++;
  }
}

$result = array();
array_walk_recursive($data, 'countleafkeys', &$result);

print_r($result);

Outputs:

2011-11-18 00:00:00
2011-11-18 00:00:00
2011-11-18 00:00:00
2011-11-22 00:00:00
2011-11-22 00:00:00
Array
(
    [2011-11-18 00:00:00] => 3
    [2011-11-22 00:00:00] => 2
)

2 Comments

+1 for using array_walk_recursive(), BTW: Is this technique some sort of en.wikipedia.org/wiki/Lambda_lifting or not??
@MGA Thanks! To be honest, Lambda lifting is a new term for me so you're probably a better judge (for now) as to whether it is or isn't. Thanks for the bedtime reading!
1
<?php
$count0=count($array[0], COUNT_RECURSIVE)-count($array[0]);
$count1=count($array[1], COUNT_RECURSIVE)-count($array[1]);

1 Comment

This is a really nice solution for 2 dimensional array counts. To get the total count: max( 0, count($array, COUNT_RECURSIVE) - count($array) ). (max(0, ...) if array is empty) (EDIT: i know this is 100% on topic, but worth to mention imo)
0

Here is my recursive variant:

$arr = array(
    '0' => array(
        '0' => array('2011-11-18 00:00:00' => 'C'),
        '1' => array('2011-11-18 00:00:00' => 'I'),
        '2' => array('2011-11-18 00:00:00' => 'S')
    ),
    '1' => array(
        '0' => array('2011-11-22 00:00:00' => 'C'),
        '1' => array('2011-11-22 00:00:00' => 'S')
    ),
    '2' => array(
        '0' => array(
            '0' => array('2011-11-22 00:00:00' => 'D')
        )
    )
);

function count_values($array, &$result = array(), $counter = 0)
{
    foreach ($array as $key => $data)
    {
        if (is_array($data))
        {
            count_values($data, $result, $counter);
        }
        else
        {
            array_key_exists($key, $result) ? $result[$key]++ : $result[$key] = 1;
        }
    }

    return $result;
}

print_r(count_values($arr));

This will return:

Array ( [2011-11-18 00:00:00] => 3 [2011-11-22 00:00:00] => 3 )

Comments

0

So so many ways to skin this cat. I reckon it comes down to code styling preference assuming no benchmarking/performance requirements.

All of these scripts produce the same result.

  • Classic nested loops (Demo)

    $result = [];
    foreach ($array as $set) {
        foreach ($set as $row) {
            foreach ($row as $k => $_) {
                $result[$k] = ($result[$k] ?? 0) + 1;
            }
        }
    }
    var_export($result);
    
  • key() and count() with one classic loop (Demo)

    $result = [];
    foreach ($array as $set) {
        $result[key($set[0])] = count($set); 
    }
    var_export($result);
    
  • Classic loop with RecursiveIterator (Demo)

    $result = [];
    $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
    foreach ($it as $k => $_) {
        $result[$k] = ($result[$k] ?? 0) + 1; 
    }
    var_export($result);
    
  • array_walk_recursive() (Demo)

    $result = [];
    array_walk_recursive(
        $array,
        function ($_, $k) use (&$result) {
            $result[$k] = ($result[$k] ?? 0) + 1;
        }
    );
    var_export($result);
    
  • COUNT_RECURSIVE then flatten (Demo)

    var_export(
        array_merge(
            ...array_map(
                fn($set) => [key($set[0]) => count($set, COUNT_RECURSIVE) - count($set)],
                $array
            )
        )
    );
    
  • array_reduce() (Demo)

    var_export(
        array_reduce(
            $array,
            fn($result, $set) => $result + [key($set[0]) => count($set)],
            []
        )
    );
    
  • Flatten, map keys, then count values (Demo)

    var_export(
        array_count_values(
            array_map(
                key(...),
                array_merge(...$array)
            )
        )
    );
    

Comments

-1

If you want count the items unidimensional and bidimensional you can try:

echo 'Size of unidimensional is: '.count($celda).'<br/>';

echo 'Size of bidimensional is: '.count($celda[0]).'<br/>';

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.