Reputation: 1168
I am trying to count elements in an array separated by one or more zeroes (0).
Example:
[1,2,4,0,9,8,4,0,0,7,1,2,6]
1+2+4, 9+8+4, 7+1+1+2+6
Output: [7,21,16]
I have written the following function:
function countElementsInArray(){
$array = [1,2,4,0,9,8,4,0,7,1,2,6];
$countArr = [];
$count = 0;
$test = 0;
for($i = 0; $i < count($array); $i++){
if( $array[$i] != 0 ) {
$count += $array[$i];
}
//else if($array[$i] == 0 || $array[$i - 1] == 0){
else{
$count = 0;
$test += 1;
}
$countArr[$test] = $count;
}
return $countArr;
}
This works fine if I have only one "0" in the array. I can't figure out how to add up the values if I have two zeroes. Any idea how to solve this problem?
EDIT: the problem is when I have array like this: [1,2,4,0,9,8,4,0,0,7,1,2,6] with two "0" next to each other: print_r(countElementsInArray())
Array ( [0] => 7 [1] => 21 [2] => 0 [3] => 16 )
and what I am trying to reach is this:
Array ( [0] => 7 [1] => 21 [2] => 16 )
Upvotes: 0
Views: 108
Reputation: 2067
This is rather late, but just for completeness, here's another solution that makes use of some of the best parts of the other answers, and accounts for things like leading zeroes, trailing zeroes, and zero sums. It's also the simplest, I believe.
function countSeparatedElements($array, $seperator = 0)
{
$array[] = $seperator;
$result = [];
$i = 0;
foreach ($array as $val) {
if ($val == $seperator) {
if (! empty($result[$i])) {
$result[$i] = array_sum($result[$i]);
$i++;
}
continue;
}
$result[$i][] = $val;
}
return ! empty($result) ? $result : false;
}
$array = [0, 1, 2, 4, 0, 9, 8, 4, 0, 0, -2, 1, 1, 0, 0, 7, 1, 2, 6, 0];
$output = countSeparatedElements($array);
print_r($output);
Output:
Array
(
[0] => 7
[1] => 21
[2] => 0
[3] => 16
)
Upvotes: 1
Reputation: 10346
In order to solve your problem with "more than one '0' in the array" you'll need to reset the sum
variable when you reach a 0
value and to increase the key
so it would start calculating the sum of the new subset of values.
Edit: In case that there are multiple zeros one next to the other, the code would unset that sum and start again with the same $i
(key).
Edit 2: Regarding @Stuart Wagner comment, in order to make sure the code doesn't unset legit sum (like: [-2,1,1]
) I added a new variable that contains the last value
($previousVal
). If that value isn't 0
and the sum
is 0
, than it's a legit zero-sum, otherwise - not.
Edit 3: As @Rizier123 mentioned in the comment, since that on the first loop $previousVal
isn't set, the main condition will return false
. The solution would be to set the variable before the loop.
Edit 4: In case of a trailing zero, simply remove it from the array as it doesn't has affect (doesn't separate between subsets).
function countElementsInArray($array){
$sumArr = array();
$i = 0;
$sumArr[$i] = 0;
$previousVal = 0;
if(last($array) == 0)
array_pop($array);
foreach($array as $val){
if($val == 0){
if($sumArr[$i] == 0 && isset($previousVal) && $previousVal == 0){
unset($sumArr[$i]);
} else {
$i++;
}
$sumArr[$i] = 0;
}
$sumArr[$i] += $val;
$previousVal = $val;
}
return $sumArr;
}
$array = [1,2,4,0,9,8,4,0,7,1,2,6];
print_r(countElementsInArray($array));
$array = [3,2,1,0,5,4,0,0,8,4];
print_r(countElementsInArray($array));
$array = [-2,1,1,0,5,4,0,0,8,4];
print_r(countElementsInArray($array));
$array = [0,0,0,-2, 1, 1, 0, 5, 4, 0,0,0, 0, 8, 4,0,-3,2,1];
print_r(countElementsInArray($array));
Output:
Array
(
[0] => 7
[1] => 21
[2] => 16
)
Array
(
[0] => 6
[1] => 9
[2] => 12
)
Array
(
[0] => 0
[1] => 9
[2] => 12
)
Array
(
[0] => 0
[1] => 9
[2] => 12
[3] => 0
)
Upvotes: 3
Reputation: 26153
$res = Array_reduce($array,
function($c, $v) {
if($v) {
if (!$c[1]) $c[0][] = $v;
else $c[0][count($c[0])-1] += $v;
$c[1]++; }
else $c[1] = 0;
return $c;
}, [[],0])[0];
Works with leading and trailing zero and empty array
$array = [0,1,2,3,0,0,-1,1,0]; // $res = array(6, 0);
$array = []; // $res = array();
Upvotes: 0
Reputation: 4207
I dont like all this loop-variable stuff much so i am going to do some regex magic:
$array = [1,2,4,0,9,8,4,0,0,7,1,2,6,0,0,0,10,20,30,0,0,0,1,2,3,6,0,0,0,4];
function custom_count($a){
$str = implode('|',$a); // array to string
$str = preg_replace('/(\|0)+/','|0',$str); // repllce multiple 0's, Regey magic
$new = explode('|',$str);
$res = [0];
$key = 0;
foreach($new as $num){
if($num == 0) {
$key++;
$res[$key] = 0;
}
else
$res[$key] += $num;
}
return $res;
}
var_dump(custom_count($array));
/*
* [0]=>
int(7)
[1]=>
int(21)
[2]=>
int(16)
[3]=>
int(60)
[4]=>
int(12)
[5]=>
int(4)
}
*/
Upvotes: 0
Reputation: 59681
This should work for you:
Here I just go through each element and add it to the $countArr
. If we hit a 0 I check, if the count array only contains 0's or not. if yes I reset the count array and continue;
else I array_sum()
the values together and reset the array.
At the end I just check if we don't have an empty array and if not I add the last sum to the $result
's array.
<?php
function countSeparatedElements(array $array) {
$countArr = [];
foreach($array as $v) {
$countArr[] = $v;
if($v == 0) {
if(count(array_unique($countArr)) === 1 && end($countArr) === 0) {
$countArr = [];
continue;
} else {
$result[] = array_sum($countArr);
$countArr = [];
}
}
}
if(!empty($countArr))
$result[] = array_sum($countArr);
return $result;
}
$array = [3, 2, 1, 0, 5, 4, 0, 0, 8, 4];
$counts = countSeparatedElements($array);
print_r($counts);
?>
output:
Array
(
[0] => 6
[1] => 9
[2] => 12
)
EDIT:
Another solution would be just to implode your string with leading commas and then explode it. After this you just can take the array_sum()
:
<?php
$array = [0, 1, 2, 4, 0, 9, 8, 4, 0, 0, -2, 1, 1, 0, 0, 7, 1, 2, 6, 0];
$str = array_reduce($array, function($keep, $v){
return $keep .= "," . $v;
}, "");
$arr = preg_split("/,0/", $str, -1, PREG_SPLIT_NO_EMPTY);
$counts = array_map(function($v){
return array_sum(explode(",", $v));
}, $arr);
print_r($counts);
?>
output:
Array
(
[0] => 7
[1] => 21
[2] => 0
[3] => 16
)
Upvotes: 0