php 将1d数组拆分为多个块,以便行计数的偏差不超过1

beq87vna  于 2023-03-16  发布在  PHP
关注(0)|答案(2)|浏览(119)

我希望尽可能均匀地将一个数组拆分为多行,并遵守每行最小计数约束,以便行计数尽可能接近最小值,并且不同行计数之间的差值永远不超过1。
换句话说,每行中的元素数不能低于$min或高于(2 * $min - 1)
例如,我有一个65个元素的数组,最小行大小约束为9。

$x = range(1, 65);
$min = 9;

我想将数组拆分为多行,其中较长的行出现在较短的行之前。

[
    [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
    [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
    [21, 22, 23, 24, 25, 26, 27, 28, 29],
    [30, 31, 32, 33, 34, 35, 36, 37, 38],
    [39, 40, 41, 42, 43, 44, 45, 46, 47],
    [48, 49, 50, 51, 52, 53, 54, 55, 56],
    [57, 58, 59, 60, 61, 62, 63, 64, 65],
]
oyt4ldly

oyt4ldly1#

经过几个小时的实验,我找到了答案:D

// i.e. count($x) = 65, min = 9
        $total = (int)floor(count($x) / $min);     // 65 : 9 = 7 (rounded down)
        $sisa = count($x) % $min;                  // 65 mod 9 = 2 (leftover)
        
        $result = [];
        $endOffset = 0;

        for ($i = 0; $i < $total; $i++){
            if ($sisa > 0){                             // 2 > 0                // 1 > 0
                $add = (int)floor($sisa / $total) + 1;  // (2 : 7) + 1 = 1      // (1 : 7) + 1 = 1

                $length = $min + $add;                  // 9 + 1 = 10           // 9 + 1 = 10
                $offset = $endOffset;                   // 0                    // 10
                
                $sisa = $sisa - $add;                   // 2 - 1 = 1            // 1 - 1 = 0
            } else {
                $offset = $endOffset;                                                                   // 20                   // 29               etc.        // 56
                $length = $min;                                                                         // 9                    // 9                etc.        // 9
            }

            $arr = array_slice(
                $x, $offset, $length
            );                                          // [0-9]                // [10-19]              // [20-28]              // [29-37]          etc.        // [56-64]
            
            $endOffset = $offset + $length;             // 0 + 10 = 10          // 10 + 10 = 20         // 20 + 9 = 29          // 29 + 9 = 38      etc.        // 56 + 9 = 65
            $result[] = $arr;
        }

        return $result;
    }
kognpnkq

kognpnkq2#

通过执行以下计算,使用array_splice()array_chunk()的方法可以代替迭代过程。

  • 输入数组的总计数($count
  • 总计数除以最小元素数的次数(整数$maxRows
  • 总计数除以$maxRows,被除数向上舍入($maxColumns
  • 总计数除以$maxRows后的余数

代码:(Demo

$count = count($array);                 // 65
$maxRows = intdiv($count, $minColumns); // 7
$maxColumns = ceil($count / $maxRows);  // 10
$longRowsCount = $count % $maxRows;     // 2

var_export([
    ...array_chunk(
        array_splice(
            $array,
            0,
            ($maxColumns * $longRowsCount) ?: $count
        ),
        $maxColumns
    ),
    ...array_chunk($array, $maxColumns - 1)
]);

两次分块尝试(都可能产生空数组)通过在数组中使用spread运算符(...)解包它们的行合并在一起。如果愿意,可以调用array_merge(),而不是解包到数组中。

相关问题