Php array нестандартная сортировка

Подскажите, пожалуйста, как решить такую задачку:

Есть некий ассоциативный массив вида:

[key_1] => Array
    (
        [0] => 0
    )
[key_2] => Array
    (
        [0] => 1
    )
[key_3] => Array
    (
        [0] => 1
    )
[key_4] => Array
    (
        [0] => 1
    )
[key_5] => Array
    (
        [0] => 0
    )
[key_6] => Array
    (
        [0] => 0
    )
[key_7] => Array
    (
        [0] => 1
    )   

Мне надо отсортировать этот массив по значению внутри каждого массива в такой вид, при этом сохранив ключи:

[key_1] => Array
    (
        [0] => 0
    )
[key_2] => Array
    (
        [0] => 1
    )
[key_5] => Array
    (
        [0] => 0
    )   
[key_3] => Array
    (
        [0] => 1
    )
[key_6] => Array
    (
        [0] => 0
    )   
[key_4] => Array
    (
        [0] => 1
    )

То есть получился массив, где значение ключей чередуются: 0|1|0|1|0|1... Всю голову сломал не пойму как это сделать.


Ответы (2 шт):

Автор решения: Алексей Шиманский

Если последовательность ключей не имеет значения, то самый простой вариант "в лоб", сделать так:

  1. Вначале применить сортировку в принципе, по значениям, чтобы был массив вида [0,0,0,0,1,1,1,1]. Здесь упрощённая схема, без упоминания ключей, чтобы было понятно.

    Тут можно применить функцию uasort

  2. Пробежаться циклом по этому массиву и собирать в новый массив по очереди вытаскавая по два значения: один с начала и один с конца, затем один второй элемент с начала и один второй элемент с конца, и т.д..... Можно двигаться попарно так: один элемент с начала и первый элемент от середины, второй элемент с начала и второй элемент с середины, и т.д.

    Для цикла может понадобиться:

    1. Пробегание от начала до середины массива (т.е. до $i < count($arr) / 2 ... В случае если число элементов нечётное то необходимо среднее число округлить в большую сторону и иметь проверку впоследствии на этот нюанс)
    2. array_slice для срезания элемента из отсортированного массива
    3. Умение формировать динамически ключ массива, например $key1 = 'key_' . ($i + 1);
    4. current для того, чтобы извлечь значение массива без ключа

Шаг №2 можно делать по-всякому и можно найти проще варианты. Но суть остаётся - вначале отсортировать, потом распихать.

Можно сделать изначально простой ассоциативный массив в виде key => value, для упрощения всех манипуляций (также подойдут для этих целей и Map)

→ Ссылка
Автор решения: Виктор Карев

Сначала собираем массив ключей, а затем пробегаем по нему двумя указателями:

$a = [
'key_1' => ['0' => 0],
'key_2' => ['0' => 1],
'key_3' => ['0' => 1],
'key_4' => ['0' => 1],
'key_5' => ['0' => 0],
'key_6' => ['0' => 0],
'key_7' => ['0' => 1],
];

$keys = array_keys($a);

$b = [];
$i = $j = $v = 0;
$count = count($a);
while ($i < $count && $j < $count && $z++ < 100) {
    while ($i < $count && $a[$keys[$i]][0] != $v /* 0 */) {
        $i++;
    }
    if ($i < $count) {
        $b[$keys[$i]] = $a[$keys[$i]];
        $i++;
        $v = 1 - $v;
    }

    while ($j < $count && $a[$keys[$j]][0] != $v /* 1 */) {
        $j++;
    }
    if ($j < $count) {
        $b[$keys[$j]] = $a[$keys[$j]];
        $j++;
        $v = 1 - $v;
    }
}
var_export($b);

Если же в массиве преобладание какого-то значения, а отбрасывать лишние значения нельзя, то не используем переменную $v, а сравниваем непосредственно с 0 и 1.

$z - техническая переменная от случайного зацикливания.

→ Ссылка