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.
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.