php 如何求多维数组最深子数组的中值?

8nuwlpux  于 2023-02-03  发布在  PHP
关注(0)|答案(2)|浏览(170)

我有一个四级多维数组,我需要对数值“leaves”按升序(ASC)排序,以便计算值的中值。
我尝试了array_walk_recursive()array_multisort()usort()等,但无法找到有效的解决方案。
以下是阵列的示意图:

(
    [2017-05-01] => Array
        (
            [DC] => Array
                (
                    [IT] => Array
                        (
                            [0] => 90
                            [1] => 0
                        )    
                    [DE] => Array
                        (
                            [0] => 18
                            [1] => 315
                            [2] => 40
                            [3] => 
                            [4] => 69
                        )    
                    [Other] => Array
                        (
                            [0] => 107
                            [1] => 46
                            [2] => 
                            [3] => 
                            [4] => 27
                            [5] => 22
                        )    
                )
        )
)
nszi6y05

nszi6y051#

这将使用输入数组的结构输出最深子数组的中值。
如果中值是空字符串,我将把中值(一个子集中的一个或两个)硬转换为整数,我还假设如果子集是空的,您将希望0作为输出。
代码:(Demo

$array=[
    '2017-05-01'=>[
        'DC'=>[
            'IT'=>[90, 0],
            'DE'=>[18, 315, 40, '', 69, 211],
            'Other'=>[107, 46, '', '', 27, 22]
        ]
    ],
    '2017-05-02'=>[
        'DC'=>[
            'IT'=>[70, 40, 55],
            'DE'=>['', 31, 4, '', 9],
            'Other'=>[1107, 12, 0, 20, 1, 11, 21]
        ]
    ],
    'fringe case'=>[
        'DC'=>[
            'IT'=>[],
            'DE'=>['', '', '', 99],
            'Other'=>['', 99]
        ]
    ]
];

foreach ($array as $k1 => $lv1) {
    foreach ($lv1 as $k2 => $lv2) {
        foreach ($lv2 as $k3 => $lv3) {
            sort($lv3);                  // order values ASC
            $count = sizeof($lv3);       // count number of values
            $index = floor($count / 2);  // get middle index or upper of middle two
            if (!$count) {               // count is zero
                $medians[$k1][$k2][$k3] = 0;
            } elseif ($count & 1) {      // count is odd
                $medians[$k1][$k2][$k3] = (int)$lv3[$index];                        // single median
            } else {                     // count is even
                $medians[$k1][$k2][$k3] = ((int)$lv3[$index-1] + (int)$lv3[$index]) / 2; // dual median
            }
        }
    }
}
var_export($medians);

输出:

array (
  '2017-05-01' => 
  array (
    'DC' => 
    array (
      'IT' => 45,
      'DE' => 54.5,
      'Other' => 24.5,
    ),
  ),
  '2017-05-02' => 
  array (
    'DC' => 
    array (
      'IT' => 55,
      'DE' => 4,
      'Other' => 12,
    ),
  ),
  'fringe case' => 
  array (
    'DC' => 
    array (
      'IT' => 0,
      'DE' => 0,
      'Other' => 49.5,
    ),
  ),
)
  • 为了记录在案,$count & 1是一个逐位比较,它确定值是否为奇数而不执行算术(并且是在PHP中执行此检查的最有效方式)。
  • 另外,如果您希望简单地覆盖输入数组的值,则可以在foreach声明中的$lv1$lv2$lv3之前写入&,然后将中值保存到$lv3Demo这样做的好处是删除了键声明,并使代码更简洁。
wgeznvg7

wgeznvg72#

事实证明,有一种方法可以使用usort()和array_walk()的组合来完成OP所寻求的任务,其中每一个都接受一个回调,如下所示:

<?php
// median code: 
//http://www.mdj.us/web-development/php-programming/calculating-the-median-average-values-of-an-array-with-php/

function calculate_median($arr) {
    sort($arr);
    $count = count($arr); //total numbers in array
    $middleval = floor(($count-1)/2); // find the middle value, or the lowest middle value
    if($count % 2) { // odd number, middle is the median
        $median = $arr[$middleval];
    } else { // even number, calculate avg of 2 medians
        $low = $arr[$middleval];
        $high = $arr[$middleval+1];
        $median = (($low+$high)/2);
    }
    return $median;
}

$a = [];
$a["2017-05-01"] = ["DC"];

$a["2017-05-01"]["DC"]["IT"] = [90,0];
$a["2017-05-01"]["DC"]["DE"] = [18,315,40,"",69];
$a["2017-05-01"]["DC"]["Other"] = [107,46,"","",27,22];

function sort_by_order ($a, $b)
{
     if ($a == "") $a = 0;
     if ($b == "") $b = 0;
     return $a - $b;
}

function test($item,$key){
    echo $key," ";
    if (is_array($item)) {
       echo array_keys($item)[1],"\n";
       $popped = array_pop($item);
       foreach ($popped as $key => $arr) {
          usort($arr, 'sort_by_order');
          echo "Median ($key): ",calculate_median( $arr ),"\n";
        }
     }
}

array_walk($a, 'test');

请参见此处的演示。另外,请参见基于OP的sandbox的示例。
虽然OP的代码没有显示引用的数组键,但要注意它们应该在实际代码中,否则PHP将使用2017-05-01进行计算,您将看到一个2011的键。
我从here中提取的中值代码。
有趣的是,通过对数字进行排序来确定中位数的传统智慧并不一定是获得这一结果的唯一方法,显然,通过找到一个主元数字并将数字序列分为三部分也可以做到这一点,而且效率可能更高(见以下回应)。

相关问题