Я ищу, чтобы иметь возможность сортировать массив многомерных массивов на нескольких столбцах. Чтобы еще больше усложнить это, я хотел бы иметь возможность устанавливать определенные параметры сортировки для каждого ключа / столбца. У меня есть то, что похоже на результат запроса БД, но на самом деле не исходит из одного, поэтому нужно сортировать его в PHP, а не в SQL.
Array ( [0] => Array ( [first_name] => Homer [last_name] => Simpson [city] => Springfield [state] => Unknown [zip] => 66735 ) [1] => Array ( [first_name] => Patty [last_name] => Bouvier [city] => Scottsdale [state] => Arizona [zip] => 85250 ) [2] => Array ( [first_name] => Moe [last_name] => Szyslak [city] => Scottsdale [state] => Arizona [zip] => 85255 ) [3] => Array ( [first_name] => Nick [last_name] => Riviera [city] => Scottsdale [state] => Arizona [zip] => 85255 ) )
Я хотел бы иметь возможность сортировать его так же, как это можно сделать с помощью запроса БД. О, а иногда колонку / ключ нужно указывать по номеру.
То, что я имел в виду, было похоже на это:
$sortOptions = array( array( 'city', SORT_ASC, SORT_STRING ), array( 'zip', SORT_DESC, SORT_NUMERIC), array( 2, SORT_ASC, SORT_STRING) // 2='last_name' ); $sorter = new MultiSort($data, $sortOptions ); $sortedData = $sorter->getSortedArray() ; print_r( $jmsSorted);
То, что я хотел бы закончить, заключается в следующем:
Array ( [0] => Array ( [first_name] => Nick [last_name] => Riviera [city] => Scottsdale [state] => Arizona [zip] => 85255 ) [1] => Array ( [first_name] => Moe [last_name] => Szyslak [city] => Scottsdale [state] => Arizona [zip] => 85255 ) [2] => Array ( [first_name] => Patty [last_name] => Bouvier [city] => Scottsdale [state] => Arizona [zip] => 85250 ) [3] => Array ( [first_name] => Homer [last_name] => Simpson [city] => Springfield [state] => Unknown [zip] => 66735 ) )
ОБНОВЛЕНИЕ: Я думаю, что в идеале решение приведет к динамическому созданию
array_multisort( $city, SORT_ASC, SORT_STRING, $zip, SORT_DESC, SORT_NUMERIC, $last_name, SORT_ASC, SORT_STRING, $inputArray);
Проблема в том, что я не хочу «жестко кодировать» эти ключевые имена там. Я попытался создать решение, основанное на примере # 3 Сортировка результатов базы данных из документации array_multisort()
которая закончилась использованием array_multisort()
но я не могу найти способ использовать мой динамически построенный список аргументов для array_multisort()
.
Моя попытка состояла в том, чтобы «объединить» эти аргументы вместе в массив, а затем
call_user_func_array( 'array_multisort', $functionArgs);
Это приводит к
Warning: Parameter 2 to array_multisort() expected to be a reference, value given in...
В PHP 5.3 каждый параметр в массиве должен быть ссылкой при вызове array_multisort()
с помощью call_user_func_array()
.
Эта функция сортирует многомерный массив и показывает способ построения массива ссылочных параметров, который работает правильно.
function msort() { $params = func_get_args(); $array = array_pop($params); if (!is_array($array)) return false; $multisort_params = array(); foreach ($params as $i => $param) { if (is_string($param)) { ${"param_$i"} = array(); foreach ($array as $index => $row) { ${"param_$i"}[$index] = $row[$param]; } } else ${"param_$i"} = $params[$i]; $multisort_params[] = &${"param_$i"}; } $multisort_params[] = &$array; call_user_func_array("array_multisort", $multisort_params); return $array; }
Пример:
$ data – это заданный массив из вопроса
$sorted_data = msort('city', SORT_ASC, SORT_STRING, 'zip', SORT_DESC, SORT_NUMERIC, $data)
Это должно работать в ситуации, которую вы описываете.
usort($arrayToSort, "sortCustom"); function sortCustom($a, $b) { $cityComp = strcmp($a['city'],$b['city']); if($cityComp == 0) { //Cities are equal. Compare zips. $zipComp = strcmp($a['zip'],$b['zip']); if($zipComp == 0) { //Zips are equal. Compare last names. return strcmp($a['last_name'],$b['last_name']); } else { //Zips are not equal. Return the difference. return $zipComp; } } else { //Cities are not equal. Return the difference. return $cityComp; } }
Вы можете сконденсировать его в одну строку следующим образом:
function sortCustom($a, $b) { return ($cityComp = strcmp($a['city'],$b['city']) ? $cityComp : ($zipComp = strcmp($a['zip'],$b['zip']) ? $zipComp : strcmp($a['last_name'],$b['last_name']))); }
Что касается настраиваемой функции сортировки, вы изобретаете колесо. Посмотрите на array_multisort()
.
Возможно, вы захотите попробовать использовать usort . Все, что вам нужно сделать, это сделать функции, которые рассказывают сортировщику, как сортировать его. Документы имеют больше информации о том, как это сделать.
Вот что я, наконец, остановился на возможность сортировки многомерных массивов. Оба вышеперечисленных ответа хороши, но я также искал что-то гибкое.
Я определенно не думаю, что есть какой-то «правильный» ответ, но это то, что работает для моих нужд и является гибким.
Как вы можете видеть из моего @link
в комментарии _usortByMultipleKeys()
он был адаптирован из комментария в руководстве PHP, который в настоящее время не существует, но я верю, что http://www.php.net/manual/en /function.usort.php#104398 – это новая версия исходного комментария. Я не изучил это новое предложение.
/** * Sort the resultSet. * * Usage: $sortOptions = array( * 'section', // Defaults to SORT_ASC * 'row' => SORT_DESC, * 'retail_price' => SORT_ASC); * $results->sortResults($sortOptions); * * @param array $sortOptions An array of sorting instructions */ public function sortResults(array $sortOptions) { usort($this->_results, $this->_usortByMultipleKeys($sortOptions)); } /** * Used by sortResults() * * @link http://www.php.net/manual/en/function.usort.php#103722 */ protected function _usortByMultipleKeys($key, $direction=SORT_ASC) { $sortFlags = array(SORT_ASC, SORT_DESC); if (!in_array($direction, $sortFlags)) { throw new InvalidArgumentException('Sort flag only accepts SORT_ASC or SORT_DESC'); } return function($a, $b) use ($key, $direction, $sortFlags) { if (!is_array($key)) { //just one key and sort direction if (!isset($a->$key) || !isset($b->$key)) { throw new Exception('Attempting to sort on non-existent keys'); } if ($a->$key == $b->$key) { return 0; } return ($direction==SORT_ASC xor $a->$key < $b->$key) ? 1 : -1; } else { //using multiple keys for sort and sub-sort foreach ($key as $subKey => $subAsc) { //array can come as 'sort_key'=>SORT_ASC|SORT_DESC or just 'sort_key', so need to detect which if (!in_array($subAsc, $sortFlags)) { $subKey = $subAsc; $subAsc = $direction; } //just like above, except 'continue' in place of return 0 if (!isset($a->$subKey) || !isset($b->$subKey)) { throw new Exception('Attempting to sort on non-existent keys'); } if ($a->$subKey == $b->$subKey) { continue; } return ($subAsc==SORT_ASC xor $a->$subKey < $b->$subKey) ? 1 : -1; } return 0; } }; }