How to count the consecutive duplicate values in an array?
It can be done simply manually:
$arr = array(1,1,1,2,2,3,3,1,1,2,2,3);
$result = array();
$prev_value = array('value' => null, 'amount' => null);
foreach ($arr as $val) {
if ($prev_value['value'] != $val) {
unset($prev_value);
$prev_value = array('value' => $val, 'amount' => 0);
$result[] =& $prev_value;
}
$prev_value['amount']++;
}
var_dump($result);
My suggestion is to extract&remove the first value from the array prior to entering the loop and use a temporary array ($carry
) to track whether each new value matches the key in the carry array. If so, increment it. If not, push the completed sequence count into the result array and overwrite the carry with the new value and set the counter to 1. When the loop finishes, push the lingering carry into the result set. My snippet does not check if the input array is empty; if necessary, add that condition to your project.
Code: (Demo)
$array = [1,1,1,2,2,3,3,1,1,2,2,3];
$result = [];
$carry = [array_shift($array) => 1];
foreach ($array as $value) {
if (isset($carry[$value])) {
++$carry[$value];
} else {
$result[] = $carry;
$carry = [$value => 1];
}
}
$result[] = $carry;
print_r($result);
Output: (condensed to reduce page bloat)
[
[1 => 3],
[2 => 2],
[3 => 2],
[1 => 2],
[2 => 2],
[3 => 1],
]
If you'd rather implement a zerkms-style, modify-by-reference style technique, the following snippet provides the same result as the above snippet.
Effectively, it pushes every newly encountered value as an associative, single-element array into the indexed result array. Because the pushed subarray is declared as a variable ($carry
) then assigned-by-reference (= &
) to the result array, incrementation of $carry
will be applied to the deeply nested value in the result array. The output array requires the additional depth in its structure so that a given value which occurs multiple times can be reliably stored.
Code: (Demo)
$result = [];
$carry = [];
foreach ($array as $value) {
if ($carry && key($carry) === $value) {
++$carry[$value];
} else {
unset($carry);
$carry = [$value => 1];
$result[] = &$carry;
}
}
unset($carry);
print_r($result);
Unsetting the reference variable $carry
after the loop may not be necessary, but if there is any potential re-use of that variable within the variable's scope, it will be important to uncouple the reference with unset()
.
And just for fun, here is a hideous regex-infused approach that works with the sample data: Demo