PHP сортировать массив по приоритету

Мне нужен метод, который сортирует массив элементов по приоритету.

Вот что я работаю до сих пор:

function arraySortPriority(array &$array, $offset, array $priorities)
{
uasort($array, function ($a, $b) use ($offset, $priorities) {
if (!isset($a[$offset])) {
$a[$offset] = null;
}
if (!isset($b[$offset])) {
$b[$offset] = null;
}
if ($a[$offset] == $b[$offset]) {
return 0;
}
$aPriority = isset($priorities[$a[$offset]])
? $priorities[$a[$offset]]
: null;
$bPriority = isset($priorities[$b[$offset]])
? $priorities[$b[$offset]]
: null;
return $aPriority > $bPriority ? -1 : 1;
});
}

// an array to sort
$array = [
['type' => 'A'],
['type' => 'A'],
['type' => 'B'],
['type' => 'B'],
['type' => 'C'],
['type' => 'C'],
['type' => 'D'],
['type' => 'D'],
['type' => 'E'],
['type' => 'E'],
['type' => 'F'],
['type' => 'F'],
['type' => 'G'],
['type' => 'G'],
['type' => 'H'],
['type' => 'H'],
['type' => 'Foo'],
['type' => 'Foo'],
['type' => 'Bar'],
['type' => 'Bar'],
[0 => 'no type should be last'],
[0 => 'no type should be last'],
];
// shuffle the array
shuffle($array);
// set priorities
$priorities = [
'A' => 8,
'B' => 7,
'C' => 6,
'D' => 5,
'E' => 4,
'F' => 3,
'G' => 2,
'H' => 1,
];
// call
arraySortPriority($array, 'type', $priorities);
// test output
foreach ($array as $item) {
if (isset($item['type'])) {
echo "{$item['type']}\r\n";
} else {
$values = array_values($item);
echo reset($values) . PHP_EOL;
}
}

Ожидаемое:

A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
Foo
Foo
Bar
Bar
no type should be last
no type should be last

Актуально:

A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
no type should be last   <-- should be at bottom
no type should be last   <-- should be at bottom
Bar
Bar
Foo
Foo

Проблема в том, что предметы, которые не получили $offset должны быть всегда отсортированы по дну.

Это означает, что no type should be last всегда следует сортировать ниже Foo или же Bar,

Как я могу это сделать?

-1

Решение

<?php

// an array to sort
$array = [
['type' => 'A'],
['type' => 'A'],
['type' => 'B'],
['type' => 'B'],
['type' => 'C'],
['type' => 'C'],
['type' => 'D'],
['type' => 'D'],
['type' => 'E'],
['type' => 'E'],
['type' => 'F'],
['type' => 'F'],
['type' => 'G'],
['type' => 'G'],
['type' => 'H'],
['type' => 'H'],
['type' => 'Foo'],
['type' => 'Foo'],
['type' => 'Bar'],
['type' => 'Bar'],
[0 => 'no type should be last'],
[0 => 'no type should be last'],
];
// shuffle the array
shuffle($array);
// set priorities
$priorities = [
'A' => 8,
'B' => 7,
'C' => 6,
'D' => 5,
'E' => 4,
'F' => 3,
'G' => 2,
'H' => 1,
];

uasort($array,function($a,$b) use ($priorities){
if(!isset($a['type'])){
if(!isset($b['type'])) return -1;
return 1;
}else if(!isset($b['type'])){
return -1;
}

if(isset($priorities[$a['type']])){
if(!isset($priorities[$b['type']])) return -1;

if($priorities[$a['type']] > $priorities[$b['type']]) return -1;
else if($priorities[$a['type']] < $priorities[$b['type']]) return 1;

}else if(isset($priorities[$b['type']])){
return 1;
}

return 0;
});

echo "<pre>";
print_r($array);

ВЫХОД

Array
(
[21] => Array
(
[type] => A
)

[8] => Array
(
[type] => A
)

[18] => Array
(
[type] => B
)

[20] => Array
(
[type] => B
)

[6] => Array
(
[type] => C
)

[16] => Array
(
[type] => C
)

[11] => Array
(
[type] => D
)

[1] => Array
(
[type] => D
)

[7] => Array
(
[type] => E
)

[17] => Array
(
[type] => E
)

[13] => Array
(
[type] => F
)

[5] => Array
(
[type] => F
)

[15] => Array
(
[type] => G
)

[9] => Array
(
[type] => G
)

[4] => Array
(
[type] => H
)

[0] => Array
(
[type] => H
)

[19] => Array
(
[type] => Bar
)

[10] => Array
(
[type] => Foo
)

[14] => Array
(
[type] => Bar
)

[12] => Array
(
[type] => Foo
)

[2] => Array
(
[0] => no type should be last
)

[3] => Array
(
[0] => no type should be last
)

)
2

Другие решения

Я решил использовать решение @ vivek_23 (отредактировано | исправлено).

Я отредактировал ненужное else и изменил возвращаемое значение на ноль, если f.e. оба смещения не установлены.

Если a и b пропускают смещение или не имеют приоритета, функция должна вернуть ноль imo.

Рабочий код:

uasort($array, function ($a, $b) use ($offset, $priorities) {
if (!isset($a[$offset])) {
return !isset($b[$offset])
? 0
: 1; // down
} elseif (!isset($b[$offset])) {
return -1; // up
}
if (isset($priorities[$a[$offset]])) {
if (!isset($priorities[$b[$offset]])) {
return -1; // up
}
return $priorities[$a[$offset]] > $priorities[$b[$offset]]
? -1 // up
: 1; // down
}
return isset($priorities[$b[$offset]])
? 1 // down
: 0;
});

Это позволяет мне использовать отрицательный приоритет, приоритет с плавающей запятой, и я не переопределяю приоритеты (см. -99999999 @Eddie solution).

проверенный

// expect A, A, B, B, C, C, ... "no type ..." at bottom
$priorities = [
'A' => 8,
'B' => 7,
'C' => 6,
'D' => 5,
'E' => 4,
'F' => 3,
'G' => 2,
'H' => 1,
];

// expect "no type ..." at bottom, ..., C, C, B, B, A, A
$priorities = [
'A' => -8,
'B' => -7,
'C' => -6,
'D' => -5,
'E' => -4,
'F' => -3,
'G' => -2,
'H' => -1,
];

// expect B, B, A, A, C, C, ... "no type ..." at bottom
$priorities = [
'A' => 6.5,
'B' => 7,
'C' => 6,
'D' => 5,
'E' => 4,
'F' => 3,
'G' => 2,
'H' => 1,
];

// expect "no type ..." at bottom, ..., C, C, A, A, B, B
$priorities = [
'A' => -6.5,
'B' => -7,
'C' => -6,
'D' => -5,
'E' => -4,
'F' => -3,
'G' => -2,
'H' => -1,
];

Спасибо @ vivek_23
🙂

1

Вы не обрабатываете случай, когда оба приоритета одинаковы.

Решение 1

Просто добавьте следующее к вашей функции перед троичным:

if ($aPriority == $bPriority)
return 0;

Так должно выглядеть так:

uasort($array, function ($a, $b) use ($offset, $priorities) {
if (!isset($a[$offset])) {
$a[$offset] = null;
}
if (!isset($b[$offset])) {
$b[$offset] = null;
}
if ($a[$offset] == $b[$offset]) {
return 0;
}

$aPriority = isset($priorities[$a[$offset]])
? $priorities[$a[$offset]]
: null;
$bPriority = isset($priorities[$b[$offset]])
? $priorities[$b[$offset]]
: null;

if ($aPriority == $bPriority)
return 0;

return $aPriority > $bPriority ? -1 : 1;
});

В противном случае вы просто предполагаете, что $ aPriority меньше, чем $ bPriority, если он не больше, но может быть равен.

Решение 2

Еще один способ добиться этого без лишнего, если в случае установить приоритет 0 вместо null если он не установлен:

$aPriority = isset($priorities[$a[$offset]])
? $priorities[$a[$offset]]
: 0;
$bPriority = isset($priorities[$b[$offset]])
? $priorities[$b[$offset]]
: 0;

Затем верните вычитание:

return $bPriority - $aPriority;

Так это будет выглядеть так:

uasort($array, function ($a, $b) use ($offset, $priorities) {
if (!isset($a[$offset])) {
$a[$offset] = null;
}
if (!isset($b[$offset])) {
$b[$offset] = null;
}
if ($a[$offset] == $b[$offset]) {
return 0;
}

$aPriority = isset($priorities[$a[$offset]])
? $priorities[$a[$offset]]
: 0;
$bPriority = isset($priorities[$b[$offset]])
? $priorities[$b[$offset]]
: 0;

return $bPriority - $aPriority;
});
0

Вы можете сделать что-то вроде:

function arraySortPriority(&$array, $offset, $priorities)
{
uasort($array, function ($a, $b) use ($offset, $priorities) {

if (!isset($a[$offset])) {
$aPriority = -99999999;             //If "type" does not exist, assign the -99999999 as priority
} else {
$aPriority = isset($priorities[$a[$offset]])
? $priorities[$a[$offset]]          //If set, set the prio value from array.
: -99999;                           //If values does not exist on $priorities. Set the this value a little bit bigger than if key is undefined.
}

if (!isset($b[$offset])) {
$bPriority = -99999999;
} else {
$bPriority = isset($priorities[$b[$offset]])
? $priorities[$b[$offset]]
: -99999;
}

return $bPriority - $aPriority;        //Just do a deduction to sort.
});
}

Это приведет к:

A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
Foo
Foo
Bar
Bar
no type should be last
no type should be last
0
По вопросам рекламы [email protected]