Сортировать массив по ключам на основе другого массива?
возможно ли в PHP сделать что-то подобное? Как бы вы пошли о написании функции? Вот вам пример. Порядок-это самое главное.
$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';
и я хотел бы сделать что-то вроде
$properOrderedArray = sortArrayByArray($customer, array('name', 'dob', 'address'));
потому что в конце я использую foreach() и они не в правильном порядке (потому что я добавляю значения в строку, которая должна быть в правильном порядке, и я не знаю заранее все ключи/значения массива).
Я посмотрел через внутренние функции массива PHP, но, похоже, вы можете сортировать только в алфавитном или числовом порядке.
15 ответов:
просто использовать
array_mergeилиarray_replace.Array_mergeработает начиная с массива, вы даете ему (в правильном порядке) и заменяя/добавляя ключи с данными из массива:$customer['address'] = '123 fake st'; $customer['name'] = 'Tim'; $customer['dob'] = '12/08/1986'; $customer['dontSortMe'] = 'this value doesnt need to be sorted'; $properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer); //Or: $properOrderedArray = array_replace(array_flip(array('name', 'dob', 'address')), $customer); //$properOrderedArray -> array('name' => 'Tim', 'address' => '123 fake st', 'dob' => '12/08/1986', 'dontSortMe' => 'this value doesnt need to be sorted')ps-я отвечаю на этот "устаревший" вопрос, потому что я думаю, что все циклы, приведенные в качестве предыдущих ответов, являются излишними.
вот так:
function sortArrayByArray(array $array, array $orderArray) { $ordered = array(); foreach ($orderArray as $key) { if (array_key_exists($key, $array)) { $ordered[$key] = $array[$key]; unset($array[$key]); } } return $ordered + $array; }
другой способ для PHP >= 5.3.0:
$customer['address'] = '123 fake st'; $customer['name'] = 'Tim'; $customer['dob'] = '12/08/1986'; $customer['dontSortMe'] = 'this value doesnt need to be sorted'; $customerSorted = array_replace(array_flip(array('name', 'dob', 'address')), $customer);результат:
Array ( [name] => Tim [dob] => 12/08/1986 [address] => 123 fake st [dontSortMe] => this value doesnt need to be sorted )отлично работает со строковыми и цифровыми клавишами.
Как насчет такого решения
$order = array(1,5,2,4,3,6); $array = array( 1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five', 6 => 'six' ); uksort($array, function($key1, $key2) use ($order) { return (array_search($key1, $order) > array_search($key2, $order)); });
function sortArrayByArray(array $toSort, array $sortByValuesAsKeys) { $commonKeysInOrder = array_intersect_key(array_flip($sortByValuesAsKeys), $toSort); $commonKeysWithValue = array_intersect_key($toSort, $commonKeysInOrder); $sorted = array_merge($commonKeysInOrder, $commonKeysWithValue); return $sorted; }
взять один массив в качестве вашего заказа:
$order = array('north', 'east', 'south', 'west');вы можете сортировать другой массив на основе значений с помощью
array_intersectDocs:/* sort by value: */ $array = array('south', 'west', 'north'); $sorted = array_intersect($order, $array); print_r($sorted);или в вашем случае, чтобы отсортировать по ключам, используйте
array_intersect_keyDocs:/* sort by key: */ $array = array_flip($array); $sorted = array_intersect_key(array_flip($order), $array); print_r($sorted);обе функции будут сохранять порядок первого параметра и будут возвращать только значения (или ключи) из второго массива.
так что для этих два стандартных случая вам не нужно писать функцию самостоятельно, чтобы выполнить сортировку/перестановку.
я использовал решение Darkwaltz4, но использовал
array_fill_keysвместоarray_flip, чтобы заполнить сNULLЕсли ключ не установлен в$array.$properOrderedArray = array_replace(array_fill_keys($keys, null), $array);
если у вас есть массив в вашем массиве, вам придется немного адаптировать функцию по Eran...
function sortArrayByArray($array,$orderArray) { $ordered = array(); foreach($orderArray as $key => $value) { if(array_key_exists($key,$array)) { $ordered[$key] = $array[$key]; unset($array[$key]); } } return $ordered + $array; }
без магии...
$array=array(28=>c,4=>b,5=>a); $seq=array(5,4,28); SortByKeyList($array,$seq) result: array(5=>a,4=>b,28=>c); function sortByKeyList($array,$seq){ $ret=array(); if(empty($array) || empty($seq)) return false; foreach($seq as $key){$ret[$key]=$dataset[$key];} return $ret; }
эта функция возвращает суб и сортированный массив на основе второго параметра $keys
function array_sub_sort(array $values, array $keys){ $keys = array_flip($keys); return array_merge(array_intersect_key($keys, $values), array_intersect_key($values, $keys)); }пример:
$array_complete = [ 'a' => 1, 'c' => 3, 'd' => 4, 'e' => 5, 'b' => 2 ]; $array_sub_sorted = array_sub_sort($array_complete, ['a', 'b', 'c']);//return ['a' => 1, 'b' => 2, 'c' => 3];
PHP имеет функции, которые помогут вам в этом:
$arrayToBeSorted = array('west', 'east', 'south', 'north'); $order = array('north', 'south', 'east', 'west'); // sort array usort($arrayToBeSorted, function($a, $b) use ($order){ // sort using the numeric index of the second array $valA = array_search($a, $order); $valB = array_search($b, $order); // move items that don't match to end if ($valA === false) return -1; if ($valB === false) return 0; if ($valA > $valB) return 1; if ($valA < $valB) return -1; return 0; });Usort делает всю работу за вас и array_search предоставляет ключи. array_search () возвращает false, когда он не может найти совпадение, поэтому элементы, которые не находятся в массиве сортировки, естественно перемещаются в нижнюю часть массива.
Примечание: uasort () упорядочит массив, не затрагивая отношения key => value.
- Сортировать по запросу
- сохранить для int-ключей (из-за array_replace)
- не возвращать ключи не существуют в inputArray
- (необязательно) ключи фильтра не существует в данном списке ключей
код:
/** * sort keys like in key list * filter: remove keys are not listed in keyList * ['c'=>'red', 'd'=>'2016-12-29'] = sortAndFilterKeys(['d'=>'2016-12-29', 'c'=>'red', 'a'=>3 ]], ['c', 'd', 'z']){ * * @param array $inputArray * @param string[]|int[] $keyList * @param bool $removeUnknownKeys * @return array */ static public function sortAndFilterKeys($inputArray, $keyList, $removeUnknownKeys=true){ $keysAsKeys = array_flip($keyList); $result = array_replace($keysAsKeys, $inputArray); // result = sorted keys + values from input + $result = array_intersect_key($result, $inputArray); // remove keys are not existing in inputArray if( $removeUnknownKeys ){ $result = array_intersect_key($result, $keysAsKeys); // remove keys are not existing in keyList } return $result; }
Первое Предложение
function sortArrayByArray($array,$orderArray) { $ordered = array(); foreach($orderArray as $key) { if(array_key_exists($key,$array)) { $ordered[$key] = $array[$key]; unset($array[$key]); } } return $ordered + $array; }Второе Предложение
$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer);Я хотел бы отметить, что оба эти предложения являются удивительными. Однако это яблоки и апельсины. В чем разница? Один из них не ассоциативно дружественный, а другой ассоциативно дружественный. Если вы используете 2 полностью ассоциативных массива, то слияние/флип массива фактически объединит и перезапишет другой ассоциативный массив. В моем случае это не те результаты, которые я искал. Я использовал настройки.ini-файл для создания массива порядка сортировки. Массив данных, который я сортировал,не нужно было переписывать моим ассоциативным сортировщиком. Таким образом, слияние массивов уничтожит мой массив данных. Оба отличные методы, оба должны быть заархивированы в любом наборе инструментов разработчиков. Исходя из ваших потребностей, вы можете обнаружить, что вам действительно нужны обе концепции в ваших архивах.
Я принял ответ от @Darkwaltz4 для его краткости и хотел бы поделиться тем, как я адаптировал решение к ситуациям, когда массив может содержать разные ключи для каждой итерации, например:
Array[0] ... ['dob'] = '12/08/1986'; ['some_key'] = 'some value'; Array[1] ... ['dob'] = '12/08/1986'; Array[2] ... ['dob'] = '12/08/1986'; ['some_key'] = 'some other value';и поддерживал "мастер-ключ" как так:
$master_key = array( 'dob' => ' ' , 'some_key' => ' ' );array_merge выполнил бы слияние в итерации Array[1] на основе $master_key и произвел ['some_key']=", пустое значение, для этой итерации. Следовательно, array_intersect_key был использован для изменения $master_key в каждой итерации так:
foreach ($customer as $customer) { $modified_key = array_intersect_key($master_key, $unordered_array); $properOrderedArray = array_merge($modified_key, $customer); }
немного поздно, но я не мог найти способ его реализации, эта версия нуждается в закрытии, php>=5.3, но может быть изменена не на:
$customer['address'] = '123 fake st'; $customer['name'] = 'Tim'; $customer['dob'] = '12/08/1986'; $customer['dontSortMe'] = 'this value doesnt need to be sorted'; $order = array('name', 'dob', 'address'); $keys= array_flip($order); uksort($customer, function($a, $b)use($keys){ return $keys[$a] - $keys[$b]; }); print_r($customer);конечно 'dontSortMe' должен быть отсортирован, и может появиться сначала в Примере
Comments