【问题标题】:Divide a two dimensional array into surfaces将二维数组划分为曲面
【发布时间】:2017-05-29 17:50:28
【问题描述】:

对于一个项目,需要根据每个平面的百分比将二维数组排列成彼此成比例的平面。 (我希望这是有道理的,否则请参见下面的示例)。在这个二维数组中,“第一”级表示行,“第二”级表示列。例如;

array(
    // row 1
    array(
        // items
        number1
        number2
        numberN
    ),
    // row 2
    array(
        // items..
    ),
    // row N
    array(
        // items..
    )
)

这个数组中的数字已经被添加/排列成面板。这些面板一起形成一个网格。每个数字代表一个项目(对于这个问题无关紧要)。我自己想出了一个解决方案。 Click here for print of the 2D array (The groups are color coded.).

可以说,共有三个组(如下所列)。这些组确实代表了上面介绍的面板。每组都有零到百之间的某个百分比。要求平面的百分比之和为百分之百。组的最大数量是七个。示例组信息;

  • 第 1 组(面板 A):70%
  • 第 2 组(面板 B):20%
  • 第 3 组(面板 C):10%

同样,这种安排应该会产生一个带有(子)面板的大面板。 As shown in this schematic figure.

我想出了将最终结果分成 4 个角的想法。每个角落都将按规则计算。这些角应该是镜像(水平和/或垂直),基于它是什么角(左上、右上、左下、右下)。

规则列表;

  • 每行的项目数应相同
  • 整个网格的纵横比应该是 2 比 1。所以宽度是高度的两倍。
  • 行数基于项目总数,因为方面是已知的。

经过几天的工作,我想出了一个工作脚本。但在某些情况下,这确实表现得很奇怪(很奇怪,不像预期的那样)。请参阅上面的当前解决方案。

所以,我的问题是;杠杆设计师如何做到这一点?这是一个已知问题吗?是否有解决方案(如算法)来解决这个(类型)问题?我长期以来一直在努力解决以下问题。在互联网上搜索,试图找到类似的问题。但我没有成功。
我不是要求一个现成的解决方案。只是一个指向正确方向的指针将不胜感激。

【问题讨论】:

  • 百分比是表示二维数组中单元格的百分比,还是值总和的百分比,还是...?如果无法准确达到百分比,该怎么办?
  • @trincot 它们代表项目的数量。因此,出于演示目的说;有 4k 个项目。第一组有 2800 个项目(因为 70%)。第二个 800 和最后一个 400。百分比将是一个近似值,而不是绝对值。
  • (1) 那么数组中的值对算法没有意义吗?他们都可能是null? (2) 平面是否可以相互“接触”,因此在一侧区域没有任何单元?或者在看到下一个区域之前,这些区域是否需要在 4 个方向中的每个方向上具有相同数量的“空间”(行/列)? (3)如果百分比太低以至于最接近的解决方案根本没有给一组细胞怎么办?这可以接受吗?
  • @trincot 是的,我相信这是真的。在“当前解决方案”中,这些值确实代表表中的记录。但它们都可以合二为一。
  • 请看我的其他问题。另外,您当前的解决方案中有什么奇怪/出乎意料的?一定有一些你没有解释的规则……

标签: php arrays matrix


【解决方案1】:

假设平面应该具有与完整矩阵大致相同的“纵横比”,您可以使用以下算法:

  • 为每个百分比计算适用于宽度和高度的系数,以获得减去可用面积百分比后剩余的确切面积。该系数是需要应用于面积的系数的平方根(与百分比有关)。

  • 由于该系数通常为非整数,请检查将宽度和高度四舍五入的方式会产生最接近所需区域的区域。

  • 对每个平面重复此操作。

代码如下:

function createPlanes($width, $height, $groupPercentages) {
    $side = 0;
    $area = $width * $height;
    $planeWidth = $width;
    $planeHeight = $height;
    $sumPct = 0;
    $coefficient2 = 1;
    foreach ($groupPercentages as $i => $pct) {
        $plane = [
            "column" => floor(($width - $planeWidth) / 2),
            "row" => floor(($height - $planeHeight) / 2),
            "width" => $planeWidth,
            "height" => $planeHeight,
        ];
        $coefficient2 -= $pct / 100;
        $coefficient = sqrt($coefficient2);
        $planeArea = $coefficient2 * $area;
        $planeWidth = $coefficient * $width;
        $planeHeight = $coefficient * $height;
        // determine all possible combinations of rounding:
        $deltas = [
            abs(floor($planeWidth) * floor($planeHeight) - $planeArea),
            abs(floor($planeWidth) * min(ceil($planeHeight), $plane["height"]) - $planeArea),
            abs(min(ceil($planeWidth), $plane["width"])  * floor($planeHeight) - $planeArea),
            abs(min(ceil($planeWidth), $plane["width"]) * min(ceil($planeHeight), $plane["height"]) - $planeArea)
        ];
        // Choose the one that brings the area closest to the required area
        $choice = array_search(min($deltas), $deltas);
        $planeWidth = $choice & 2 ? ceil($planeWidth) : floor($planeWidth);        
        $planeHeight = $choice & 1 ? ceil($planeHeight) : floor($planeHeight);
        $newSumPct = ($area - $planeWidth * $planeHeight) / $area * 100;
        $plane["pct"] = $newSumPct - $sumPct;
        $sumPct = $newSumPct;
        $planes[] = $plane;
    }
    return $planes;
}

// Example call for a 2D array with 20 columns and 32 rows, and
// three percentages: 10%, 20%, 70%:
$planes = createPlanes(20, 32, [10, 20, 70]);

$planes 变量会得到这个内容:

array (
  array (
    'column' => 0,
    'row' => 0,
    'width' => 20,
    'height' => 32,
    'pct' => 10.9375,
  ),
  array (
    'column' => 0,
    'row' => 1,
    'width' => 19,
    'height' => 30,
    'pct' => 20,
  ),
  array (
    'column' => 1,
    'row' => 3,
    'width' => 17,
    'height' => 26,
    'pct' => 69.0625,
  ),
)

内部属性定义平面的起始位置(行、列)、大小(高度、宽度),以及平面相对于总面积的实际百分比。

请注意,实际的 2D 不需要是算法的一部分,因为它的值不会影响它。

【讨论】:

  • 非常感谢您花时间思考这个问题。但我相信我之前的解释是不完整的,可以解释。您提供的示例并没有解决我的问题:(我确实编辑了我的问题并添加了重要信息。您能再看看吗?
  • 很抱歉,我在您的编辑中没有看到我的回答无法处理的任何规则。另一方面,我昨天问了几个问题(在你的问题的 cmets 中),你只回答了 1 个。也许你最好用你期望的输出来制定一个例子。如果数字不重要,那么在该示例中只使用所有 1 值,以避免人们开始认为它们表示对算法很重要的东西。
猜你喜欢
  • 1970-01-01
  • 2013-04-27
  • 2018-05-03
  • 2015-05-10
  • 2013-01-08
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多