Сортировка массива по ключам на основе другого массива?

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
164
0
150 245
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

Вот и все:

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;
}

Значит, вы можете соединить 2 массива знаком +? Я никогда этого не знал, я использовал array_merge()!

alex 25.09.2009 03:08

Это лучше, чем использование usort() или uasort()?

grantwparks 25.09.2009 23:57

Вы должны вставить оператор break, как только значение будет найдено.

Adel 26.09.2011 18:50

@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].

flu 05.08.2015 11:07

Безопасно ли использовать знак +?

crmpicco 12.11.2015 17:57

+ или оператор объединения совершенно допустим в соответствии с Документация PHP в некоторых случаях использования, это именно то, что вам нужно, если вам нужно сохранить числовые ключи.

Hexodus 13.05.2017 00:14
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_intersect­Docs:

/* sort by value: */
$array = array('south', 'west', 'north');
$sorted = array_intersect($order, $array);
print_r($sorted);

Или в вашем случае для сортировки по ключам используйте array_intersect_key­Docs:

/* sort by key: */
$array = array_flip($array);
$sorted = array_intersect_key(array_flip($order), $array);
print_r($sorted);

Обе функции сохранят порядок первого параметра и будут возвращать только значения (или ключи) из второго массива.

Таким образом, для этих двух стандартных случаев вам не нужно самостоятельно писать функцию для выполнения сортировки / перегруппировки.

Пересечение избавится от тех записей, о которых он заранее не знает.

DanMan 06.03.2013 19:02

Это неверно для сортировки по ключам. array_intersect_key будет возвращать значения только из array1, а не array2

spooky 21.01.2015 17:30

Согласен с pavsid - пример array_intersect_key неверен - он возвращает значения из первого массива, а не из второго.

Jonathan Aquino 15.04.2015 06:18
Ответ принят как подходящий

Просто используйте 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: «Если входные массивы имеют одинаковые строковые ключи, то более позднее значение для этого ключа будет перезаписывать предыдущее. Однако если массивы содержат числовые ключи, более позднее значение не будет перезаписывать исходное значение, но будет добавлено ".

bolbol 07.11.2012 10:52

Хорошо, но что делать, если ключей в значениях нет? Мне это нужно, но только в том случае, если существует какой-либо из ключей ... Наверное, тогда на нем нужен foreach ...

Solomon Closson 09.05.2014 02:49

в моем случае это array_replace вместо array_merge. array_merge объединяет оба значения вместо того, чтобы заменять второй массив упорядоченными ключами.

neofreko 12.11.2014 09:26

@bolbol Используйте array_replace, как предлагал @neofreko, и он также работает с цифровыми клавишами.

Ariel 23.05.2016 21:02

Я наткнулся на ваше решение пару лет назад в поисках чего-то другого - и подумал про себя, что это чрезвычайно эффективно по сравнению с циклами. Теперь мне нужно ваше решение, и мне потребовался час поиска, чтобы найти его снова! Спасибо!

Michael 13.11.2017 06:29

Кроме того, если массив 'order' (т.е. array ('name', 'dob', 'address')) имеет больше ключей, чем массив для сортировки, тогда дополнительный array_intersect полученного отсортированного массива с исходным массивом будет отключен случайные ключи, которые были добавлены в array_merge.

bbe 08.01.2018 13:24

Чтобы исправить @bbe, вы должны использовать array_intersect_key, потому что он сравнивает ключи, а не значения. (в случае, если значения не сопоставимы, например: если они массивы)

A.Marques 25.02.2019 14:45

Действительно ли необходимо использовать array_flip вместо объявления ключей массива с пустыми значениями?

Miguel Vieira 09.09.2020 19:30

Первое предложение

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().

Jason McCreary 07.02.2014 19:25
array_replace также оставляет неизменным тип переменной. Если бы одним из значений в вашем массиве было (string) '1', и вы использовали бы оператор +, значение было бы преобразовано в (int) 1.
halfpastfour.am 17.10.2014 13:24

Это также работает с цифровыми клавишами (array_merge() просто добавил бы их?). Логика очень хорошо объяснена здесь. Первый, array_flip() изменяет значения массива $ order на ключи. Второй, array_replace() заменяет значения первого массива значениями с такими же ключами во втором массиве. Если вам нужно отсортировать массив по ключам от другого, вам даже не нужно использовать array_flip.

aexl 14.12.2017 14:58

В 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)).

TheOperator 23.01.2020 12:12

Немного поздно, но я не смог найти способ, которым я это реализовал, эта версия требует закрытия, 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, и он может появиться первым в примере.

  • сортировать по запросу
  • сохранить для 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;
}

Эта функция возвращает вспомогательный и отсортированный массив на основе второго параметра $ 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)));

VladSavitsky 22.01.2021 16:49

Без магии ...

$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, чтобы оно соответствовало имени параметра.

kursus 20.09.2018 13:37

Другие вопросы по теме