用模数排序

时间:2012-02-25 15:34:49

标签: php sorting matrix modulus

我正在尝试使用uksort将列表排序到列中。

数组已经进行了alpha排序,因此它就像array('A','B','C','D','E','F','G','H','I','J','K','L','M')

以html形式显示,作为浮动元素:

A B C D
E F G H
I J K L
M

我希望它重新排序,所以显示如下:

A E H K
B F I L
C G J M
D

因此排序的数组将是:array('A','E','H','K','B','F','I','L','C','G','J','M','D'

基本上,与Sorting a list alphabetically with a modulus相同,但对于php。我已经尝试将javascript的解决方案转换为php,但我没有得到正确的答案。任何人都有任何关于如何在PHP中这样做的想法?

这就是我的尝试:

function cmp_nav_by4($a, $b) {
    if (($a % 5) < ($b % 5)) {
        return 1;
    } elseif (($a % 4) > ($b % 4)) {
        return -1;
    } else {
        return $a < $b ? 1 : -1;
    }
}
$result = uksort($thearray, "cmp_nav_by4");

2 个答案:

答案 0 :(得分:6)

设置以下内容:

$array = range('A', 'M');
$columns = 4;
$length = count($array);

print_matrix($array, $columns);

通过索引(行和列)输出每个成员及其键,以及顶部的元素顺序:

One row - A B C D E F G H I J K L M
A[ 0] B[ 1] C[ 2] D[ 3] 
E[ 4] F[ 5] G[ 6] H[ 7] 
I[ 8] J[ 9] K[10] L[11] 
M[12] 

链接的javascript代码可以很容易地转换为PHP。但是,如果你仔细观察那个问题/答案,很明显它只适用于完整的行,就像我以前的尝试一样:

function callback_sort($array, $columns)
{
    $sort = function($columns)
    {
        return function($a, $b) use ($columns)
        {
            $bycol = ($a % $columns) - ($b % $columns);
            return $bycol ? : $a - $b;
        };
    };

    uksort($array, $sort(4));

    return $array;
}

输出:

One row - A E I M B F J C G K D H L
A[ 0] E[ 4] I[ 8] M[12] 
B[ 1] F[ 5] J[ 9] C[ 2] 
G[ 6] K[10] D[ 3] H[ 7] 
L[11] 

所以只是在另一个问题中提供的功能不起作用。

但是由于数组已经排序,因此您无需再次对其进行排序,只需更改顺序或元素即可。但是哪个订单呢?如果矩阵不完整,例如完全填充n x n,每列需要计算不同的新索引。采用13个元素(A-M)的示例为您提供了每列的以下行分布:

column: 1 2 3 4
rows:   4 3 3 3

因此,每列的值都不同。例如,在索引12处,第13个元素位于第4行。在前往该位置的路上,它已经通过第1列4次,在其他列2-4中通过3次。因此,要获得迭代索引的虚拟索引,您需要总结每列中的频率,以找出原始索引中有多少数字。如果您超过最大成员数,则继续为0。

所以这可以通过逐步推进每个索引来迭代解决,以便在索引上分配计算:

Index 0:
    No column: 0

Index 1:
    1x in column is which has 4 rows: 4

Index 2:
    1x in column 1 (4 rows) and 1x in other columns (3 rows): 4 + 3

......等等。如果虚拟索引超过12,它将从0开始,例如对于第5个元素(索引4),虚拟索引将计算13:

Index 4:
    1x 4 rows and 3x 3 rows = 13 (4 + 9)
    13 > 12 => 1 (13 - 12)

现在通过从虚拟索引0开始填充新数组并每次给出相应的偏移量(查看您所在的列,添加该列的行数,必要时换行)将给出所需的输出:

One row - A E H K B F I L C G J M D
A[ 0] E[ 4] H[ 7] K[10] 
B[ 1] F[ 5] I[ 8] L[11] 
C[ 2] G[ 6] J[ 9] M[12] 
D[ 3] 

用代码编写,这比原始索引简单foreach。通过维护键的索引,这适用于任何数组,甚至包含字符串键的数组:

$floor = floor($length/$columns);
$modulo = $length % $columns;
$max = $length-1;
$virtual = 0;
$keys = array_keys($array);
$build = array();
foreach($keys as $index => $key)
{
    $vkey = $keys[$virtual];
    $build[$vkey] = $array[$vkey];
    $virtual += $floor + ($index % $columns < $modulo);
    ($virtual>$max) && $virtual %= $max;
}

print_matrix($build, $columns);

就是这样:DemoGist

答案 1 :(得分:1)

@hakre有正确的代码答案。原因:

底层排序函数Zend_qsort实际上并没有对元素和键重新排序。相反,它重新排序zend引擎使用的内部数组桶。如果您使用数字索引的数组进行ksort,然后使用$q = count($array);for($i=0; $i<$q); $i++)进行迭代,它将像以前一样返回值;如果你用for($key in $array)进行迭代,你将获得新的密钥排序。