使用模数排序

发布于 2025-01-08 18:33:00 字数 853 浏览 0 评论 0原文

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

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

基本上与 对列表进行排序相同按字母顺序排列modulus 但对于 php. 我已经尝试采用 javascript 的解决方案并将其转换为 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");

I am trying trying to sort a list into columns with uksort.

The array already alpha sorted, so it is like array('A','B','C','D','E','F','G','H','I','J','K','L','M')

Which gets displayed in html, as floated elements:

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

I want it reordered so it displays like this:

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

So the sorted array would be: array('A','E','H','K','B','F','I','L','C','G','J','M','D'

Basically, the same as Sorting a list alphabetically with a modulus but for php. I've tried taking the solution for javascript and convert it into php, but I'm not getting something right. Anyone have any ideas of how to do this in php?

This is what I have tried:

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");

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

雨夜星沙 2025-01-15 18:33:00

设置以下内容:

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

所以只是另一个问题中提供的函数不起作用。

但由于数组已经排序,您不需要再次排序,只需更改顺序或元素即可。但哪个顺序呢?如果矩阵不完整,例如nx n完全填充,则每列都需要计算不同的新索引。以包含 13 个元素 (AM) 的示例为例,每列的行分布如下:

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

就是这样:演示要点

Setting up the following:

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

print_matrix($array, $columns);

Which outputs each member and it's key by index (row and colum) and as well the elements order on top:

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] 

The javascript code linked could be easily converted to PHP. However, if you look closely to that question/answer, it becomes clear that it only work with full rows, like with my previous attempt:

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;
}

Output:

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] 

So it's just that the function provided in the other question does not work.

But as the array is already sorted, you don't need to sort it again but just to change the order or elements. But which order? If the matrix is not complete e.g. n x n fully filled, per each column, a different new index needs to be calculated. Taken the example with 13 elements (A-M) gives you the following distribution of rows per column:

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

So per each column, the value differs. For example at index 12, the 13th element is in the 4th row. On the way coming to that position, it has been passed 4 times through column 1 and 3 times in the other columns 2-4. So to get the virtual index of the iterated index, you need so sum how often you've been in each column to find out how many numbers in the original index you were going forward. If you go over the maximum number of members, you continue over at 0.

So this could be iteratively solved by stepping forward per each index to distribute the calculation over the indexes:

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

... and so on. If the virtual index goes over 12, it will start at 0, for example for the 5th Element (index 4) the virtual index would calculate 13:

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

Now filling a new array by starting with the virtual index 0 and giving the appropriate offset each time (look in which column you are, add the number of rows of that column, wrap around if necessary) will give the desired output:

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] 

Written in code, that's a simple foreach over the original indexes. By maintaining an index of keys as well, this works with any array, even those with string keys:

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

And that's it: Demo, Gist.

天冷不及心凉 2025-01-15 18:33:00

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

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

@hakre has the correct code answer. The why:

The underlying sort function, Zend_qsort, does not actually reorder the elements and keys. Instead, it reorders the internal array buckets the zend engine uses. If you ksort a numerically indexed array, then iterate over with $q = count($array);for($i=0; $i<$q); $i++) it will return the values exactly as before; if you iterate with for($key in $array) you will get they new key ordering.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文