Я пытаюсь отсортировать многомерный массив по нескольким ключам и понятия не имею, с чего начать. Я посмотрел на uasort(), но не совсем уверен, как написать функцию для того, что мне нужно. Мне нужно отсортировать по «state», затем по «event_type», затем по «date_start». Мой массив выглядит следующим образом:
[
['ID' => 1, 'title' => 'Boring Meeting', 'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 3, 'title' => 'Mario Party', 'date_start' => '2010-07-22', 'event_type' => 'party', 'state' => 'new-york'],
['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party', 'state' => 'california']
]
Мой желаемый результат таков:
[
['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party', 'state' => 'california']
['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 1, 'title' => 'Boring Meeting', 'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 3, 'title' => 'Mario Party', 'date_start' => '2010-07-22', 'event_type' => 'party', 'state' => 'new-york'],
]
Ответ 1
Тебе нужно использовать array_multisort:
$mylist = array(
array('ID' => 1, 'title' => 'Boring Meeting', 'event_type' => 'meeting'),
array('ID' => 2, 'title' => 'Find My Stapler', 'event_type' => 'meeting'),
array('ID' => 3, 'title' => 'Mario Party', 'event_type' => 'party'),
array('ID' => 4, 'title' => 'Duct Tape Party', 'event_type' => 'party')
);
# получить список колонок сортировки и их данные для передачи в array_multisort
$sort = array();
foreach($mylist as $k=>$v) {
$sort['title'][$k] = $v['title'];
$sort['event_type'][$k] = $v['event_type'];
}
# сортировка по event_type по убыванию, а затем по title по возрастанию
array_multisort($sort['event_type'], SORT_DESC, $sort['title'], SORT_ASC,$mylist);
Начиная с PHP 5.5.0:
array_multisort(array_column($mylist, 'event_type'), SORT_DESC,
array_column($mylist, 'title'), SORT_ASC,
$mylist);
$mylist теперь:
array (
0 => array (
'ID' => 4,
'title' => 'Duct Tape Party',
'event_type' => 'party',
),
1 => array (
'ID' => 3,
'title' => 'Mario Party',
'event_type' => 'party',
),
2 => array (
'ID' => 1,
'title' => 'Boring Meeting',
'event_type' => 'meeting',
),
3 => array (
'ID' => 2,
'title' => 'Find My Stapler',
'event_type' => 'meeting',
),
)
Ответ 2
PHP7 делает сортировку по нескольким столбцам СУПЕРлегкой с помощью оператора (<=>), он же «Комбинированный оператор сравнения» или «Оператор трехстороннего сравнения».
Ресурс: https://wiki.php.net/rfc/combined-comparison-operator
Сортировка по нескольким столбцам так же проста, как запись сбалансированных/реляционных массивов с обеих сторон оператора. Когда значение $a находится слева от оператора «<=>», а значение $b - справа, используется сортировка ASCending. Когда значение $b находится слева от оператора «<=>», а значение $a - справа, используется сортировка DESCending. Когда оператор «<=>» сравнивает две числовые строки, он сравнивает их как числа - таким образом, вы автоматически получаете естественную сортировку. Я не использовал uasort(), потому что не вижу необходимости сохранять исходные индексы.
Код сортирует по «state» ASC, затем «event_type» ASC, затем «date_start» ASC
$array = [
['ID' => 1, 'title' => 'Boring Meeting', 'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 3, 'title' => 'Mario Party', 'date_start' => '2010-07-22', 'event_type' => 'party', 'state' => 'new-york'],
['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party', 'state' => 'california']
];
usort($array, function($a, $b) {
return [$a['state'], $a['event_type'], $a['date_start']]
<=>
[$b['state'], $b['event_type'], $b['date_start']];
});
var_export($array);
Вывод:
array (
0 => array (
'ID' => 4,
'title' => 'Duct Tape Party',
'date_start' => '2010-07-28',
'event_type' => 'party',
'state' => 'california',
),
1 => array (
'ID' => 2,
'title' => 'Find My Stapler',
'date_start' => '2010-07-22',
'event_type' => 'meeting',
'state' => 'new-york',
),
2 => array (
'ID' => 1,
'title' => 'Boring Meeting',
'date_start' => '2010-07-30',
'event_type' => 'meeting',
'state' => 'new-york',
),
3 => array (
'ID' => 3,
'title' => 'Mario Party',
'date_start' => '2010-07-22',
'event_type' => 'party',
'state' => 'new-york',
),
)
Пример для PHP7.4 и выше:
usort($array, fn($a, $b) =>
[$a['state'], $a['event_type'], $a['date_start']]
<=>
[$b['state'], $b['event_type'], $b['date_start']]
);
Эквивалентная техника с array_multisort() и вызовом array_column() для каждого критерия сортировки:
array_multisort(
array_column($array, 'state'),
array_column($array, 'event_type'),
array_column($array, 'date_start'),
$array
);
Ответ 3
Вы можете сделать это с помощью usort. Аргумент $cmp_function может быть таким:
function my_sorter($a, $b) {
$c = strcmp($a['state'], $b['state']);
if($c != 0) {
return $c;
}
$c = strcmp($a['event_type'], $b['event_type']);
if($c != 0) {
return $c;
}
return strcmp($a['date_start'], $b['date_start']);
}
Для произвольного количества полей в PHP 5.3 вы можете использовать закрытия для создания функции сравнения:
function make_cmp($fields, $fieldcmp='strcmp') {
return function ($a, $b) use (&$fields) {
foreach ($fields as $field) {
$diff = $fieldcmp($a[$field], $b[$field]);
if($diff != 0) {
return $diff;
}
}
return 0;
}
}
usort($arr, make_cmp(array('state', 'event_type', 'date_start')))
Для произвольного количества полей различных типов в PHP 5.3:
function make_cmp($fields, $dfltcmp='strcmp') {
# присвоить массив в случае, если у $fields нет элементов
$fieldcmps = array();
# назначить функцию сравнения для полей, для которых не задана функция сравнения
foreach ($fields as $field => $cmp) {
if (is_int($field) && ! is_callable($cmp)) {
$field = $cmp;
$cmp = $dfltcmp;
}
$fieldcmps[$field] = $cmp;
}
return function ($a, $b) use (&$fieldcmps) {
foreach ($fieldcmps as $field => $cmp) {
$diff = call_user_func($cmp, $a[$field], $b[$field]);
if($diff != 0) {
return $diff;
}
}
return 0;
}
}
function numcmp($a, $b) {
return $a - $b;
}
function datecmp($a, $b) {
return strtotime($a) - strtotime($b);
}
/**
* Приоритет выше; приоритет 2 наступает раньше, чем 1.
*/
function make_evt_prio_cmp($priorities, $default_priority) {
return function($a, $b) use (&$priorities) {
if (isset($priorities[$a])) {
$prio_a = $priorities[$a];
} else {
$prio_a = $default_priority;
}
if (isset($priorities[$b])) {
$prio_b = $priorities[$b];
} else {
$prio_b = $default_priority;
}
return $prio_b - $prio_a;
};
}
$event_priority_cmp = make_evt_prio_cmp(
array('meeting' => 5, 'party' => 10, 'concert' => 7),
0);
usort($arr, make_cmp(array('state', 'event' => $event_priority_cmp, 'date_start' => 'datecmp', 'id' => 'numcmp')))
Ответ 4
Я попытался выполнить приведенный ниже код так:
$songs = array(
'1' => array('artist'=>'Smashing Pumpkins', 'songname'=>'Soma'),
'2' => array('artist'=>'The Decemberists', 'songname'=>'The Island'),
'3' => array('artist'=>'Fleetwood Mac', 'songname' =>'Second-hand News')
);
вызов функции сортировки массива:
$songs = subval_sort($songs,'artist');
print_r($songs);
функция сортировки массива:
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
функция обратной сортировки массива:
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
arsort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
Web