7

我有以下数组:

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

它是使用array_count_values()PHP 中的函数创建的。

在 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] =>
)

这些是年龄,那么我怎样才能将它们分组到年龄组中呢?

假设我想要以下年龄段:<= 18 19-26 27-32 > 32

它应该看起来:

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

有为此准备好的功能吗?

我的解决方案:一种乏味的方法是创建年龄组的变量。如果键匹配范围,则比 foreach 并增加特定年龄组的变量 ++ ($min <= $value) && ($value <= $max)...

4

4 回答 4

10

有趣的问题。这是我的解决方案。首先,定义一个年龄范围数组:

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

然后,我们有你的array_count_values()输出:

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

现在,我们创建一个包含所有年龄的数组,其中键是年龄,值是具有该年龄的人数。下一步需要按其键对其进行排序。

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

最后,我遍历所有年龄范围,从$all_ages数组中切出年龄范围,并将它们的值相加以生成一个年龄范围数组,其值对应于该年龄范围内的人数。

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

Aprint_r( $result); 产生以下输出

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

编辑:由于您仍然可以访问原始数组,因此您可以计算最后有多少“未知数”:

$result['unknown'] = count( array_filter( $original_array,  function( $el) { 
    return empty( $el); 
}));
于 2013-03-15T14:16:22.957 回答
8

这听起来像是 map-reduce 的完美案例。

映射步骤:将每个年龄变成 4 个范围之一。

减少步骤:将范围转换为范围的结果数组。

让我们试一试:

$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';
}

所以基本上在这里,我们只是将每个年龄转换为它所代表的范围的字符串表示。所以现在我们将有一个范围数组,所以我们需要将其简化为一个摘要(将所有这些范围相加):

然后是reduce函数:

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

这很简单。如果您想支持动态范围,那么您将有一些逻辑来检查是否未设置年龄(然后将其初始化为0)...

所以现在,把它们放在一起:

$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));

然后产生:

array(4) { 
    ["unknown"]=> int(0)
    ["<= 18"]=> int(3) 
    ["19-26"]=> int(2) 
    ["26-32"]=> int(0) 
    ["> 32"]=> int(2) 
}
于 2013-03-15T15:51:14.397 回答
1

如果您只想使用以前的数组array_count_values(),可以使用

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

创建一个空白数组来填充

$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);

$final 的输出:

array (size=5)
  'unknown' => int 2
  18 => int 1
  '19_26' => int 4
  '27_32' => int 1
  32 => int 0
于 2013-03-15T14:27:34.693 回答
1

在看到所有这些解决方案之后,我想为什么不将正则表达式与原始数组一起使用?

$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);

输出:

Array
(
    [0-17] => 2
    [18-26] => 3
    [27-32] => 1
    [33-159] => 2
)
于 2013-03-15T15:28:14.603 回答