1

我不确定如何以最好的方式解释我想做的事情。但我要试一试!我有一个这样的数组:

$array = array(
    "a" => array(
         "key1" => 3,
         "key2" => 4,
         "key3" => 1
    ),
    "b" => array(
         "key1" => 4,
         "key2" => 5,
         "key3" => 2
    ),
    "c" => array(
         "key1" => 2,
         "key2" => 3,
         "key3" => 3
    ),
    "d" => array(
         "key1" => 1,
         "key2" => 2,
         "key3" => 2
    )
);

注意:数组会更大,并且值不会只是那些(但总是会是整数)。

如何将这个数组分成两半,每个部分都有来自每个不同键的相似平均值(key1 的平均值相似,key2 的平均值相似,key3 的平均值相似)?

在上面的例子中,结果应该是:

$array[0] = array(
    "a" => array(
         "key1" => 3,
         "key2" => 4,
         "key3" => 1
    ),
    "c" => array(
         "key1" => 2,
         "key2" => 3,
         "key3" => 3
    )
);

$array[1] = array(
    "b" => array(
         "key1" => 4,
         "key2" => 5,
         "key3" => 2
    ),
    "d" => array(
         "key1" => 1,
         "key2" => 2,
         "key3" => 2
    )
);

(两个数组的 key1 的平均值为 2.5,key2 的平均值为 3.5,key3 的平均值为 2)

4

1 回答 1

0

以下功能改编自Hacker's Delight 网站

function combos($bits, $max=32){
    $out = array();
    if ($bits < 1 || $bits > $max || $max > 32) return $out;
    $x = pow(2, $bits) - 1;
    $last = $x * pow(2, ($max - $bits));
    while($x <= $last){
        $out[] = decbin($x);
        $smallest = ($x & -$x);
        $ripple = $smallest + $x;
        $new_smallest = ($ripple & -$ripple);
        $ones = (($new_smallest/$smallest) >> 1) - 1;
        $x = $ripple | $ones;
    }
    return $out;
}

以下功能是可选的。如果有奇数个子数组,或者子数组中的项目不相等,它会准备数组。如果项目不相等,则用 0 填充子数组。如果子数组的数量是奇数,它用零填充项加一:

function array_prep($arr){
    $cnt = 0;
    foreach ($arr as $key => $value){
        $cnt = (count($value) > $cnt) ? count($value) : $cnt;
    }
    if (count($arr)%2 == 1){
        $arr[] = array_fill(0, $cnt, 0);
    }
    foreach ($arr as $key => $value){
        $arr[$key] = array_pad($value, $cnt, 0);
    }
    return $arr;
}

这是平衡子数组的主要代码:

$array = array_prep($array);//remove if prepping is unnecessary
$n = count($array);
$cmb = combos(floor($n/2), $n-1);
array_unshift($array, null);
$rows = call_user_func_array('array_map', $array);
array_shift($array);
$score = array_combine($cmb, array_fill(0, count($cmb), 0));
foreach ($rows as $key => $row){
    foreach ($score as $combo => $val){
        $c = str_split(str_pad($combo, $n, '0', STR_PAD_LEFT));
        $sc = 0;
        foreach ($row as $k => $i){
            $sc += $i*(1 - 2*$c[$k]);
        }
        $score[$combo] += abs($sc);
    }
}
$min = array_keys($score, min($score));
$winner = str_split(str_pad($min[0], $n, '0', STR_PAD_LEFT));
//hack to keep original keys associated with values
foreach ($winner as $key => $value){
    $winner[$key] = $n*$value + $key; 
}
$winner_copy = $winner;
$keys = array_keys($array);
array_multisort($winner, $array);
array_multisort($winner_copy, $keys);
$array = array_combine($keys, $array);
$arr1 = array_slice($array, 0, floor($n/2));
$arr2 = array_slice($array, floor($n/2));
于 2013-07-26T07:47:33.483 回答