4

我正在尝试使用 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'

基本上,与使用模数按字母顺序排序列表相同,但对于 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");
4

2 回答 2

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

于 2012-02-25T15:56:48.853 回答
1

@hakre 有正确的代码答案。为什么:

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

于 2012-02-25T23:05:29.577 回答