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


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

Author: JasonMArcher, 2008-12-08

15 answers

Просто используйте 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 - Я отвечаю на этот "устаревший" вопрос, потому что я думаю, что все циклы, приведенные в качестве предыдущих ответов, являются излишними.

 285
Author: Darkwaltz4, 2016-05-23 18:01:43

Вот так:

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;
}
 94
Author: Eran Galperin, 2016-09-30 00:48:49

Другой способ для 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
)

Отлично работает со строковыми и цифровыми клавишами.

 33
Author: ekbUser, 2013-03-31 13:48:24

Как насчет этого решения

$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));
});
 27
Author: Peter de Groot, 2014-11-25 13:59:12
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;
}
 21
Author: OIS, 2008-12-08 05:27:22

Возьмите один массив в качестве вашего заказа:

$order = array('north', 'east', 'south', 'west');

Вы можете отсортировать другой массив на основе значений с помощью array_intersect Документы:

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

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

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

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

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

 14
Author: hakre, 2011-12-28 18:20:52

Я использовал решение Darkwaltz4, но использовал array_fill_keys вместо array_flip, чтобы заполнить NULL, если ключ не установлен в $array.

$properOrderedArray = array_replace(array_fill_keys($keys, null), $array);
 3
Author: Baptiste Bernard, 2017-06-27 08:07:00

ЕСЛИ у вас есть массив в вашем массиве, вам придется немного адаптировать функцию с помощью 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;
}
 2
Author: Boombastic, 2009-10-29 21:22:48

Без магии...

$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;
}
 2
Author: Jenovai Matyas, 2018-04-06 09:48:37

Эта функция возвращает вложенный и отсортированный массив, основанный на втором параметре $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];
 1
Author: Doglas, 2017-01-31 12:31:34

В 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() упорядочит массив, не влияя на отношения ключ =>значение.

 0
Author: danielcraigie, 2014-10-25 15:12:21
  • сортировка по запросу
  • сохранить для 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;
}
 0
Author: Grain, 2016-12-29 10:21:57

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

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, чтобы создайте мой массив порядка сортировки. Массив данных, который я сортировал, не нужно было переписывать моим коллегой по ассоциативной сортировке. Таким образом, слияние массивов уничтожит мой массив данных. Оба метода являются отличными, оба должны быть заархивированы в любом наборе инструментов разработчиков. Исходя из ваших потребностей, вы можете обнаружить, что вам действительно нужны обе концепции в ваших архивах.

 0
Author: user1653711, 2017-08-10 08:29:40

Я принял ответ от @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 выполнил бы слияние в итерации массива[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);
}
 0
Author: Pageii Studio, 2017-09-26 08:50:51

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

 -1
Author: DJules, 2015-10-29 13:13:06