将数组键分组到数字范围,可能吗?

时间:2013-03-15 13:49:40

标签: php arrays

我有以下数组:

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

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

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

这是否有现成功能?

我的解决方案: 1繁琐的方法是创建年龄组的变量。如果密钥匹配范围($min <= $value) && ($value <= $max) ...

,则为foreach并增加特定年龄组的变量++

4 个答案:

答案 0 :(得分:9)

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

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

print_r( $result); yields the following output

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

答案 1 :(得分:7)

这听起来像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) 
}

答案 2 :(得分: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

答案 3 :(得分:1)

在看到所有这些解决方案之后,我想为什么不将Regex与原始阵列一起使用?

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