Are array group keys in numeric ranges possible?

I have the following array:

( [25] => 1 [26] => 3 [10] => 2 [24] => 1 ) 

It was created using the array_count_values() function in PHP.

The actual source array was something like this before array_count_values โ€‹โ€‹...

 Array ( [0] => 26 [1] => [2] => 18 [3] => 28 [4] => 22 [5] => 21 [6] => 26 [7] => [8] => [9] => [10] => [11] => [12] => [13] => [14] => [15] => [16] => [17] => [18] => [19] => [20] => ) 

These are ages, so how can I group them into age groups?

Suppose I need the following age groups: <= 18 19-26 27-32 > 32

It is supposed to see:

 ( [<= 18] => 1 [19-26] => 4 [27-32] => 2 [ > 32] => 1 ) 

Is there a ready-made function for this?

My solution: 1 tedious way would be to create variable age groups. Than foreach and increase the ++ variable for a specific age group if the key match is in the range ($min <= $value) && ($value <= $max) ...

+7
source share
4 answers

An interesting problem. Here is my solution. First, define an array of age ranges:

 $age_ranges = array( array( 0, 18), array( 19, 26), array( 27, 32), array( 33, 150) // I use 150 as the "max" age ); 

Then we get your output from array_count_values() :

 $array_count_values = array( 25 => 1, 26 => 3, 10 => 2, 24 => 1); // From OP 

Now we create an array of all ages, where keys are age and values โ€‹โ€‹are the number of people with this age. You need to sort it by its keys for the next step.

 $all_ages = $array_count_values + array_fill( 0, 150, 0); ksort( $all_ages); 

Finally, I iterate over all age ranges, separate the age range from the $all_ages and summarize their values โ€‹โ€‹to create an array of age ranges, and its values โ€‹โ€‹correspond to the number of people in this age range.

 $result = array(); foreach( $age_ranges as $range) { list( $start, $end) = $range; $result["$start-$end"] = array_sum( array_slice( $all_ages, $start, $end - $start + 1)); } 

A print_r( $result); outputs the following result :

 Array ( [0-18] => 2 [19-26] => 5 [27-32] => 0 [33-150] => 0 ) 

Edit: Since you still have access to the original array, you can simply calculate how many โ€œunknownsโ€ you had at the very end:

 $result['unknown'] = count( array_filter( $original_array, function( $el) { return empty( $el); })); 
+9
source

It sounds like the perfect case of a card cut.

Map step: turn each age into one of 4 ranges.

Reduce step: include the range in the array of results from the range.

Try:

 $map = function($age) { if (!$age) { return 'unknown'; } elseif ($age <= 18) { return '<= 18'; } elseif ($age <= 26) { return '19-26'; } elseif ($age <= 32) { return '26-32'; } return '> 32'; } 

So basically here we just turn each age into a string representation of the range that it represents. So now we will have an array of ranges, so we need to reduce this to a summary (add all these ranges):

And then the reduction function:

 $reduce = function($result, $age) { $result[$age]++; return $result; } 

It is pretty simple. If you want to support dynamic ranges, then you will have some kind of logic to check if the age is set (and then initialize it to 0 ) ...

So now all together:

 $array = array(12, 63, 24, 34, 12, 10, 19,); // Your ages $data = array_map(function($age) { if (!$age) { return 'unknown'; } elseif ($age <= 18) { return '<= 18'; } elseif ($age <= 26) { return '19-26'; } elseif ($age <= 32) { return '26-32'; } return '> 32'; }, $array); $result = array_reduce($data, function($result, $age) { $result[$age]++; return $result; }, array('unknown' => 0, '<= 18' => 0, '19-26' => 0, '26-32' => 0, '> 32' => 0)); 

What then gives:

 array(4) { ["unknown"]=> int(0) ["<= 18"]=> int(3) ["19-26"]=> int(2) ["26-32"]=> int(0) ["> 32"]=> int(2) } 
+7
source

If you just want to use the array that you had before array_count_values() , you can use

 $ages = array( 0 => 26, 1 => 18, 2 => 28, 3 => 22, 4 => null, 5 => 21, 6 => 26, 7 => null); 

create an empty array to fill

 $final = array( 'unknown' => 0, '18' => 0, '19_26' => 0, '27_32' => 0, '32' => 0, ); array_walk($ages, function($age, $i, $final) { if (!$age) { $final['unknown']++; return; } if ($age <= 18) { $final['18']++; return; } if ($age <= 26) { $final['19_26']++; return; } if ($age <= 32) { $final['27_32']++; return; } if ($age > 32) { $final['32']++; return; } }, &$final); 

output from $ final:

 array (size=5) 'unknown' => int 2 18 => int 1 '19_26' => int 4 '27_32' => int 1 32 => int 0 
+1
source

After looking through all these solutions, I thought, why not use Regex with the original array?

 $ages = array(25, 26, 10, 24, 10, 26, 26, 32, 32, 54, 84, 4, 18, 5, 98, 27); $string = '#'. implode('#', $ages) . '#'; preg_match_all('/(#[0-9]#|#1[0-7]#)|(#1[8-9]#|#2[0-6]#)|(#2[7-9]#|#3[0-2]#)|(#3[3-9]#|#[4-9][0-9]#|#1[0-5][0-9]#)/', $string, $groups); $age_ranges = array('0-17' => count(array_filter($groups[1])), '18-26' => count(array_filter($groups[2])), '27-32' => count(array_filter($groups[3])), '33-159' => count(array_filter($groups[4]))); print_r($age_ranges); 

Output:

 Array ( [0-17] => 2 [18-26] => 3 [27-32] => 1 [33-159] => 2 ) 
+1
source

All Articles