Сортировка по модулю - PullRequest
       3

Сортировка по модулю

3 голосов
/ 25 февраля 2012

Я пытаюсь отсортировать список по столбцам с помощью uksort.

Массив уже отсортирован по альфа, поэтому он выглядит как 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");

Ответы [ 2 ]

6 голосов
/ 25 февраля 2012

Настройка следующего:

$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-й строке.На пути к этой позиции она была пройдена 4 раза через столбец 1 и 3 раза в других столбцах 2-4.Таким образом, чтобы получить виртуальный индекс итерированного индекса, вам нужно сложить, как часто вы были в каждом столбце, чтобы выяснить, сколько чисел в исходном индексе вы ожидали.Если вы превысите максимальное число членов, вы продолжите с 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);

И все: Demo , Gist .

1 голос
/ 26 февраля 2012

@ Хакре имеет правильный код ответа. Почему:

Основная функция сортировки, Zend_qsort, фактически не переупорядочивает элементы и ключи. Вместо этого он переупорядочивает внутренние массивы, которые использует движок Zend. Если вы сортируете численно индексированный массив, затем итерируете с $q = count($array);for($i=0; $i<$q); $i++), он вернет значения точно так же, как и раньше; если вы выполните итерацию с for($key in $array), вы получите новый порядок ключей.

...