Próbuję posortować tablicę wielowymiarową według wielu kluczy i nie mam pojęcia, od czego zacząć. Spojrzałem na uasort, ale nie byłem pewien, jak napisać funkcję dla tego, czego potrzebuję.
Muszę posortować według stanu, następnie typ_zdarzenia, a następnie datę.
Moja tablica wygląda tak:
Array
(
[0] => Array
(
[ID] => 1
[title] => Boring Meeting
[date_start] => 2010-07-30
[time_start] => 06:45:PM
[time_end] =>
[state] => new-york
[event_type] => meeting
)
[1] => Array
(
[ID] => 2
[title] => Find My Stapler
[date_start] => 2010-07-22
[time_start] => 10:45:AM
[time_end] =>
[state] => new-york
[event_type] => meeting
)
[2] => Array
(
[ID] => 3
[title] => Mario Party
[date_start] => 2010-07-22
[time_start] => 02:30:PM
[time_end] => 07:15:PM
[state] => new-york
[event_type] => party
)
[3] => Array
(
[ID] => 4
[title] => Duct Tape Party
[date_start] => 2010-07-28
[time_start] => 01:00:PM
[time_end] =>
[state] => california
[event_type] => party
)
...... etc
php
arrays
sorting
multidimensional-array
attepted_nerd
źródło
źródło
Odpowiedzi:
Potrzebujesz
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') ); # get a list of sort columns and their data to pass to array_multisort $sort = array(); foreach($mylist as $k=>$v) { $sort['title'][$k] = $v['title']; $sort['event_type'][$k] = $v['event_type']; } # sort by event_type desc and then title asc array_multisort($sort['event_type'], SORT_DESC, $sort['title'], SORT_ASC,$mylist);
Od PHP 5.5.0:
array_multisort(array_column($mylist, 'event_type'), SORT_DESC, array_column($mylist, 'title'), SORT_ASC, $mylist);
$mylist
jest teraz: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', ), )
źródło
array_column
funkcji github.com/ramsey/array_column . Dzięki temu możliwe jest użycie bardziej eleganckiego sposobu z drugiego fragmentu kodu w starszych wersjach.Możesz to zrobić za pomocą
usort
.$cmp_function
Argumentem mogą być: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']); }
W przypadku dowolnej liczby pól w PHP 5.3 możesz użyć domknięć, aby utworzyć funkcję porównawczą:
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')))
Dla dowolnej liczby pól różnych typów w PHP 5.3:
function make_cmp($fields, $dfltcmp='strcmp') { # assign array in case $fields has no elements $fieldcmps = array(); # assign a comparison function to fields that aren't given one 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); } /** * Higher priority come first; a priority of 2 comes before 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')))
źródło
PHP7 Sprawia, że sortowanie według wielu kolumn jest BARDZO łatwe dzięki operatorowi statku kosmicznego (
<=>
), znanemu jako „operator porównania łączonego” lub „operator porównania trójstronnego”.Zasób: https://wiki.php.net/rfc/combined-comparison-operator
Sortowanie według wielu kolumn jest tak proste, jak pisanie tablic zrównoważonych / relacyjnych po obu stronach operatora. To łatwe!
Nie używałem,
uasort()
ponieważ nie widzę potrzeby zachowywania oryginalnych indeksów.Kod: ( Demo )
$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);
Wynik
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', ), )
ps Arrow składnia w PHP7.4 i nowszych ( Demo ) ...
usort($array, fn($a, $b) => [$a['state'], $a['event_type'], $a['date_start']] <=> [$b['state'], $b['event_type'], $b['date_start']] );
Równoważna technika zi
array_multisort()
wywołaniearray_column()
dla wszystkich kryteriów sortowania to: ( Demo )array_multisort( array_column($array, 'state'), array_column($array, 'event_type'), array_column($array, 'date_start'), $array );
źródło
class Sort { private $actual_order = 'asc'; private $actual_field = null; public function compare_arrays($array1, $array2) { if ($array1[$this->actual_field] == $array2[$this->actual_field]) { return 0; } elseif ($array1[$this->actual_field] > $array2[$this->actual_field]) { return ($this->actual_order == 'asc' ? 1 : -1); } else { return ($this->actual_order == 'asc' ? -1 : 1); } } public function order_array(&$array) { usort($array, array($this, 'compare_arrays')); } public function __construct ($field, $actual_order = 'asc') { $this->actual_field = $field; $this->actual_order = $actual_order; } } // use $sort = new Sort ("state"); $sort->order_array($array);
źródło
Próbowałem poniżej kodu i pomyślnie
kod tablicy
$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') );
wywołanie funkcji sortowania tablicy
$songs = subval_sort($songs,'artist'); print_r($songs);
funkcja sortowania tablicy
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; }
if tablica odwrotna funkcja sortowania
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; }
źródło
Ulepszając genialny kod @Stijn Leenknegt, oto moja pragmatyczna funkcja 2 centów:
$data[] = array('volume' => 67, 'edition' => 2); $data[] = array('volume' => 86, 'edition' => 1); $data[] = array('volume' => 85, 'edition' => 6); $data[] = array('volume' => 98, 'edition' => 2); $data[] = array('volume' => 86, 'edition' => 6); $data[] = array('volume' => 67, 'edition' => 7); function make_cmp(array $sortValues) { return function ($a, $b) use (&$sortValues) { foreach ($sortValues as $column => $sortDir) { $diff = strcmp($a[$column], $b[$column]); if ($diff !== 0) { if ('asc' === $sortDir) { return $diff; } return $diff * -1; } } return 0; }; } usort($data, make_cmp(['volume' => "desc", 'edition' => "asc"]));
źródło
if ($diff) { return $diff * ($sortDir === 'asc' ? 1 : -1); }
Może to komuś pomoże:
// data to sort $output = 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') ); // multi column, multi direction order by $body['order_by'] = array( array("field"=> "event_type", "order"=> "desc"), array("field"=> "title", "order"=> "asc"), array("field"=> "ID", "order"=> "asc"), ); $output = $this->multiColumnMultiDirectionSort($body, $output); public function multiColumnMultiDirectionSort(array $body, array $output) { // get order fields and its direction in proper format $orderFieldDirection = []; if (!empty($body['order_by']) && is_array($body['order_by'])) { foreach ($body['order_by'] as $order) { $orderDirection = $order['order'] == "desc" ? SORT_DESC : SORT_ASC; // we need format that array_multisort supports $orderFieldDirection[$order['field']] = $orderDirection; } } if (!empty($orderFieldDirection)) { // get the list of sort columns and their data in the format that is required by array_multisort $amParams = []; $sort = []; foreach ($orderFieldDirection as $field => $order) { foreach ($output as $k => $v) { $sort[$field][$k] = $v[$field]; } $amParams[] = $sort[$field]; $amParams[] = $order; $amParams[] = SORT_REGULAR; // this is not needed, but we can keep as it might come handy in the future } $amParams[] = &$output; // very important to pass as reference call_user_func_array("array_multisort", $amParams); } return $output; }
źródło
jeśli chcesz posortować tablicę wielowymiarową
pierwsza tablica to:
$results['total_quote_sales_person_wise']['quote_po'];
drugi to:
$results['total_quote_sales_person_wise']['quote_count'];
ta tablica wielowymiarowa, którą chcesz posortować malejąco za jednym razem, a następnie użyj tego kodu:
array_multisort($results['total_quote_sales_person_wise']['quote_po'],SORT_DESC, $results['total_quote_sales_person_wise']['quote_count'],SORT_DESC);
źródło