将 1d 数组拆分为块,以便行计数的偏差永远不会超过 1

问题描述 投票:0回答:2

我想尽可能均匀地将数组拆分成行,遵守每行最小计数约束,以便行数尽可能接近最小值,并且不同行数之间的差异永远不会超过 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],
]
php arrays multidimensional-array grouping chunks
2个回答
1
投票

经过数小时的试验,我找到了答案 :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;
    }

0
投票

通过执行以下计算,使用

array_splice()
array_chunk()
的方法可以替代迭代过程。

  • 输入数组的总数 (
    $count
    )
  • 总计数除以最小元素数为整数的次数(
    $maxRows
    )
  • 总数除以
    $maxRows
    ,股息四舍五入 (
    $maxColumns
    )
  • 总数除以
    $maxRows
  • 后的余数

代码:(演示

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

这两个分块尝试(其中任何一个都可能产生一个空数组)通过使用数组内部的扩展运算符(

...
)解包它们的行来合并在一起。如果愿意,可以调用
array_merge()
而不是解包到数组中。

© www.soinside.com 2019 - 2024. All rights reserved.