3

I have tried solutions to many similar questions, but they all seem to give me a count for each array. So I have the following array:

Array
(
    [1] => Array
        (
            [0] => 1
            [1] => 12
            [2] => 2
        )

    [2] => Array
        (
            [0] => 1
            [1] => 13
            [2] => 3
        )

    [3] => Array
        (
            [0] => 1
            [1] => 12
            [2] => 2
        )

    [4] => Array
        (
            [0] => 1
        )

    [5] => Array
        (
            [0] => 1
        )

)

I am trying to count the duplicates across all arrays. So the output should show:

Five 1's
Two 12's
One 13
Two 2's

At the moment I am trying:

foreach($data as $key => $row) {
    print_r(array_count_values($row));
}

Which outputs the counts for each individual array

Array
(
    [1] => 1
    [12] => 1
    [2] => 1
)
Array
(
    [1] => 1
    [13] => 1
    [3] => 1
)
Array
(
    [1] => 1
    [12] => 1
    [2] => 1
)
Array
(
    [1] => 1
)
Array
(
    [1] => 1
)

I have also tried this:

foreach ($data as $key => $row) {
    $counts = array_count_values(array_column($data, $key));
    var_dump($counts);
}

Which seems to miss a lot of information, like the count of the 1's

array(2) {
  [12]=>
  int(2)
  [13]=>
  int(1)
}
array(2) {
  [2]=>
  int(2)
  [3]=>
  int(1)
}
array(0) {
}
array(0) {
}
array(0) {
}

As a note, the initial array keys will not always be sequential, as this represents a row number. So this array may contain rows 1, 2, 5, 6, 7 etc.

How would I go about counting all duplicates together?

2
  • 1
    please always post array data from var_export() calls to help volunteers to support you faster. Commented Oct 13, 2018 at 22:34
  • Thank you, will do going forward, didn't know about this functions Commented Oct 13, 2018 at 22:37

3 Answers 3

4

Since your array is not flattened, you will need to visit each value and increment unless you want to call merging functions.

Code: (Demo)

$array = [
    1 => [1, 12, 2],
    2 => [1, 13, 3],
    3 => [1, 12, 2],
    4 => [1],
    5 => [1]
];

//           make the generated value available outside of function scope
//           \-------------------------------v--------------------------/
array_walk_recursive($array, function($v)use(&$output) {  // visit each leafnode
    if (isset($output[$v])) {  // check if the key has occurred before
        ++$output[$v];         // increment
    } else {
        $output[$v] = 1;       // declare as 1 on first occurrence
    }
});

var_export($output);

Output:

array (
  1 => 5,
  12 => 2,
  2 => 2,
  13 => 1,
  3 => 1,
)

Or, non-recursively:

foreach ($array as $row) {
    foreach ($row as $v) {
        if (isset($output[$v])) { // check if the key has occurred before
            ++$output[$v];        // increment
        } else {
            $output[$v] = 1;      // declare as 1 on first occurrence
        }
    }
}

Or, a functional one-liner to flatten then count:

var_export(array_count_values(array_reduce($array, 'array_merge', array())));

Or, a functional one-liner with the splat operator to flatten then count:

var_export(array_count_values(array_merge(...$array)));
Sign up to request clarification or add additional context in comments.

1 Comment

I think this idea works better for my situation, thanks
2

You can do this quite easily by using an accumulator array and iterating all the elements:

$result = [];
foreach ($data as $row) {
    foreach($row as $value) {
        $result[$value] = isset($result[$value]) ? $result[$value] + 1 : 1;
    }
}
var_dump($result);

3 Comments

Wow, think I was trying to think too hard! Thanks
Definitely avoid posting code that generates Notices. (people will copy-paste this stuff)
Please don't assume that the researchers have a certain level of development skill. Always post your best code. If you know there is a better way to code something, always post that. This will help to make this site more valuable and help you to earn more points in the long run.
1

You can use call_user_func_array to merge all the individual arrays, and then array_count_values on that result:

$data = array
(array(1, 12, 2),
 array(1, 13, 3),
 array(1, 12, 2),
 array(1),
 array(1)
 );

print_r(array_count_values(call_user_func_array('array_merge', $data)));

Output:

Array
(
    [1] => 5
    [12] => 2
    [2] => 2
    [13] => 1
    [3] => 1
)

1 Comment

Flattening first is a good idea too. I was just about to add this to my list of solutions.

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.