Можно ли в 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, но, похоже, вы можете сортировать их только по алфавиту или по цифрам.






Вот и все:
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;
}
Это лучше, чем использование usort() или uasort()?
Вы должны вставить оператор break, как только значение будет найдено.
@alex Будьте очень осторожны при замене array_merge() оператором массива +. Он объединяется по ключу (также для цифровых ключей) и из слева направо, в то время как array_merge объединяется из справа налево и никогда не перезаписывает числовые ключи. Например. [0,1,2]+[0,5,6,7] = [0,1,2,7], тогда как array_merge([0,1,2],[0,5,6,7]) = [0,1,2,0,5,6,7] и ['a' => 5] + ['a' => 7] = ['a' => 5], но array_merge(['a' => 5], ['a' => 7]) = ['a' => 7].
Безопасно ли использовать знак +?
+ или оператор объединения совершенно допустим в соответствии с Документация PHP в некоторых случаях использования, это именно то, что вам нужно, если вам нужно сохранить числовые ключи.
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;
}
ЕСЛИ у вас есть массив в вашем массиве, вам придется немного адаптировать функцию Эрана ...
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;
}
Возьмите в качестве заказа один массив:
$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);
Обе функции сохранят порядок первого параметра и будут возвращать только значения (или ключи) из второго массива.
Таким образом, для этих двух стандартных случаев вам не нужно самостоятельно писать функцию для выполнения сортировки / перегруппировки.
Пересечение избавится от тех записей, о которых он заранее не знает.
Это неверно для сортировки по ключам. array_intersect_key будет возвращать значения только из array1, а не array2
Согласен с pavsid - пример array_intersect_key неверен - он возвращает значения из первого массива, а не из второго.
Просто используйте 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 - Я отвечаю на этот «устаревший» вопрос, потому что считаю, что все циклы, указанные в предыдущих ответах, излишни.
Он отлично работает, если у вас есть строковые ключи, но нет числовых. Документы PHP: «Если входные массивы имеют одинаковые строковые ключи, то более позднее значение для этого ключа будет перезаписывать предыдущее. Однако если массивы содержат числовые ключи, более позднее значение не будет перезаписывать исходное значение, но будет добавлено ".
Хорошо, но что делать, если ключей в значениях нет? Мне это нужно, но только в том случае, если существует какой-либо из ключей ... Наверное, тогда на нем нужен foreach ...
в моем случае это array_replace вместо array_merge. array_merge объединяет оба значения вместо того, чтобы заменять второй массив упорядоченными ключами.
@bolbol Используйте array_replace, как предлагал @neofreko, и он также работает с цифровыми клавишами.
Я наткнулся на ваше решение пару лет назад в поисках чего-то другого - и подумал про себя, что это чрезвычайно эффективно по сравнению с циклами. Теперь мне нужно ваше решение, и мне потребовался час поиска, чтобы найти его снова! Спасибо!
Кроме того, если массив 'order' (т.е. array ('name', 'dob', 'address')) имеет больше ключей, чем массив для сортировки, тогда дополнительный array_intersect полученного отсортированного массива с исходным массивом будет отключен случайные ключи, которые были добавлены в array_merge.
Чтобы исправить @bbe, вы должны использовать array_intersect_key, потому что он сравнивает ключи, а не значения. (в случае, если значения не сопоставимы, например: если они массивы)
Действительно ли необходимо использовать array_flip вместо объявления ключей массива с пустыми значениями?
Первое предложение
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 полностью ассоциативных массива, то объединение / отражение массивов фактически объединит и перезапишет другой ассоциативный массив. В моем случае это не те результаты, которые я искал. Я использовал файл settings.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.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
)
Прекрасно работает со строковыми и цифровыми клавишами.
+ Хотя они оба работают, я обнаружил, что array_replace() лучше передает намерение, чем array_merge().
array_replace также оставляет неизменным тип переменной. Если бы одним из значений в вашем массиве было (string) '1', и вы использовали бы оператор +, значение было бы преобразовано в (int) 1.
Это также работает с цифровыми клавишами (array_merge() просто добавил бы их?). Логика очень хорошо объяснена здесь. Первый, array_flip() изменяет значения массива $ order на ключи. Второй, array_replace() заменяет значения первого массива значениями с такими же ключами во втором массиве. Если вам нужно отсортировать массив по ключам от другого, вам даже не нужно использовать array_flip.
В 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 () упорядочит массив, не влияя на отношения ключ => значение.
Как насчет этого решения
$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));
});
Это не очень эффективно. Для каждого сравнения выполняется два линейных поиска в массиве. Если предположить, что временная сложность uksort () равна O(n * log n), то этот алгоритм работает в O(n^2 * log(n)).
Немного поздно, но я не смог найти способ, которым я это реализовал, эта версия требует закрытия, 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, и он может появиться первым в примере.
Код:
/**
* 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;
}
Эта функция возвращает вспомогательный и отсортированный массив на основе второго параметра $ 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];
Я использовал решение Darkwaltz4, но использовал array_fill_keys вместо array_flip, чтобы заполнить NULL, если ключ не установлен в $array.
$properOrderedArray = array_replace(array_fill_keys($keys, null), $array);
Чтобы удалить элементы из массива $, которые не указаны в $ keys, я использовал: array_replace(array_fill_keys($keys, null), array_intersect_key($array, array_flip($keys)));
Без магии ...
$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;
}
Это прекрасно работает, спасибо, просто обновите $dataset, чтобы оно соответствовало имени параметра.
Значит, вы можете соединить 2 массива знаком +? Я никогда этого не знал, я использовал
array_merge()!