0

I need to count the unique key-value pairs in an array of arrays (regardless of which row they come from).

Sample input:

$info = [
    ['car' => 'Audi', 'previous_car' => 'BMW'],
    ['car' => 'Audi', 'previous_car' => 'Seat'],
    ['car' => 'Audi', 'previous_car' => 'BMW'],
    ['car' => 'BMW',  'previous_car' => 'BMW'],
    ['car' => 'Ford', 'previous_car' => 'Seat'],
];

Desired output:

[
    'car' => [
        'Audi' => 3,
        'BMW' => 1,
        'Ford' => 1
    ],
    'previous_car' => [
        'BMW' => 3,
        'Seat' => 2
    ]
]

I tried to use array_value_count(), but I doesn't work well on multidimensional arrays.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
mephisto4
  • 22
  • 5
  • this question will help you which is lalready asked here.. http://stackoverflow.com/questions/6460993/get-the-keys-for-duplicate-values-in-an-array – Muhammad Irfan Apr 11 '14 at 09:36
  • possible duplicate of [Count specific values in multidimensional array](http://stackoverflow.com/questions/11558397/count-specific-values-in-multidimensional-array) – Lal krishnan S L Apr 11 '14 at 09:54

5 Answers5

4

If you're running PHP 5.5, you can use:

$newArray = array(
    'car' => array_count_values(array_column($info, 'car')),
    'previous_car' => array_count_values(array_column($info, 'previous_car'))
);
var_dump($newArray);

For versions of PHP prior to 5.5

$newArray = array(
    'car' => array_count_values(
        array_map(
            function($value) {
                return $value['car'];
            },
            $info
        )
    ),
    'previous_car' => array_count_values(
        array_map(
            function($value) {
                return $value['previous_car'];
            },
            $info
        )
    )
);
var_dump($newArray);
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
2

In a more object orientated way you can solve it as follows

$values = new ArrayObject();
$iterator = new RecursiveArrayIterator($info);
iterator_apply($iterator, 'countDistinct', array($iterator, $values));

function countDistinct($iterator, $values) {
    while ( $iterator -> valid() ) {
        if ( $iterator -> hasChildren() ) {
            countDistinct($iterator -> getChildren(), $values);
        } else {
            if (!$values->offsetExists($iterator->key())) {
                $values->offsetSet($iterator->key(), new ArrayObject());
            }

            if (!$values->offsetGet($iterator->key())->offsetExists($iterator->current())) {
                $values->offsetGet($iterator->key())
                    ->offsetSet($iterator->current(), 1);
            } else {
                $values->offsetGet($iterator->key())
                    ->offsetSet($iterator->current(),
                $values->offsetGet($iterator->key())->offsetGet($iterator->current()) + 1);
            }
        }

        $iterator -> next();
    }
}

Sure, with this example you do not avoid the loop. But with the ArrayObject and the RecursiveArrayIterator you will have some memory and performance advantages.

The result of this will exactly match your expected result, which you can easyliy iterate with the getIterator() function of the ArrayObject.

Marcel
  • 4,854
  • 1
  • 14
  • 24
0

Here is what might help you:

$returnArray = array('car' => NULL, 'previous_car' => NULL);

foreach($info as $newInfo) {
    $returnArray['car'][] = $newInfo['car'];
    $returnArray['previous_car'][] = $newInfo['previous_car'];
}

$ret['car'] = array_count_values($returnArray['car']);
$ret['previous_car'] = array_count_values($returnArray['previous_car']);

var_dump($ret);

This returns:

array (size=2)
  'car' => 
    array (size=3)
      'Audi' => int 3
      'BMW' => int 1
      'Ford' => int 1
  'previous_car' => 
    array (size=2)
      'BMW' => int 3
      'Seat' => int 2
Guns
  • 2,678
  • 2
  • 23
  • 51
0

I don't think I'd recommend any native functions for this task. Using nested foreach() loops will probably be cleanest. Use each row's key and value as the first and second level keys and increment tally with each occurrence.

Code: (Demo)

$result = [];
foreach ($info as $row) {
    foreach ($row as $k => $v) {
        $result[$k][$v] = ($result[$k][$v] ?? 0) + 1;
    }
}
var_export($result);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
-1

You can write a function that will sort your data but for now check this out: http://www.php.net/manual/en/function.array-multisort.php

smg628
  • 179
  • 1
  • 5