Как отсортировать многомерный массив по одному из полей внутреннего массива в PHP? - PullRequest
19 голосов
/ 11 марта 2010

Предположим, у меня есть массив, который имитирует таблицу базы данных. Каждый элемент массива представляет строку, а внутри каждой строки есть другой массив, содержащий имена и значения полей.

Array
(
    [0] => Array
        (
            [name] => 'Sony TV'
            [price] => 600.00
        )

    [1] => Array
        (
            [name] => 'LG TV'
            [price] => 350.00
        )

    [2] => Array
        (
            [name] => 'Samsung TV'
            [price] => 425.00
        )  
}

Что я хочу сделать, так это отсортировать строки (элементы внешнего массива) по цене. Ниже приведен пример того, чего я хочу достичь:

Array
(
    [0] => Array
        (
            [name] => 'LG TV'
            [price] => 350.00
        )

    [1] => Array
        (
            [name] => 'Samsung TV'
            [price] => 425.00
        )

    [2] => Array
        (
            [name] => 'Sony TV'
            [price] => 600.00
        )        
}

Как видите, мне не нужно сохранять ключи внешнего массива.

Ответы [ 8 ]

35 голосов
/ 11 марта 2010

Вам необходимо использовать usort , функцию, которая сортирует массивы через пользовательскую функцию. Что-то вроде:

function cmp($a, $b)
{
    if ($a["price"] == $b["price"]) {
        return 0;
    }
    return ($a["price"] < $b["price"]) ? -1 : 1;
}

usort($yourArray,"cmp")
14 голосов
/ 31 декабря 2017

Это всего лишь один лайнер

array_multisort( array_column($yourArray, "price"), SORT_ASC, $yourArray );

Вы также можете найти его здесь: http://php.net/manual/en/function.array-multisort.php

поиск "array_column" на этой странице руководства.

14 голосов
/ 11 марта 2010

Вы можете использовать usort():

function sort($a, $b) {
    if ($a['price'] == $b['price']) return 0;
    return ($a['price'] > $b['price']) ? 1 : -1;
}

usort($array, 'sort');

Еще лучше, если вы создадите такой класс для повторного использования кода:

class FieldSorter {
    public $field;

    function __construct($field) {
        $this->field = $field;
    }

    function cmp($a, $b) {
        if ($a[$this->field] == $b[$this->field]) return 0;
        return ($a[$this->field] > $b[$this->field]) ? 1 : -1;
    }
}

$sorter = new FieldSorter('price');    
usort($array, array($sorter, "cmp"));

Таким образом, вы можете легко сортировать по другим полям.

И хотя вы сказали, что ключи внешнего массива не нужно сохранять, вы можете легко добиться этого, используя uasort() вместо usort.

3 голосов
/ 12 апреля 2018

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

$column = 'price';
usort($table, function($a, $b) use ($column) {
    return $a[$column] <=> $b[$column];
});

Теперь вы можете использовать анонимную функцию для обратного вызова сравнения (начиная с PHP 5.3), а в PHP 7 введен оператор комбинированного сравнения (<=>), который позволяет вам уменьшить логику сравнения

if ($a['price'] == $b['price']) return 0;
return ($a['price'] > $b['price']) ? 1 : -1;

в одном выражении

return $a[$column] <=> $b[$column];
1 голос
/ 23 февраля 2017

Этот вопрос немного стар, но оставит здесь ответ на будущее.

От php.net-Multisort Функция мы можем использовать код ниже;

    $data= [['volume' => 67, 'edition' => 2],['volume' => 85, 'edition' => 6],...];
foreach ($data as $key => $row) {
    $volume[$key]  = $row['volume'];
    $edition[$key] = $row['edition'];
}
array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);

Выше приведено для статической сортировки данных, когда вы вручную изменяете столбцы сортировки.

Для более динамичного и надежного примера рассмотрим ниже;

Предположим, у меня есть данные ниже;

$data   = [[1, 'Amanda', 'Wright', 'awright0@usnews.com', 'Female', '135.114.57.89', 31237],
           [2, 'Theresa', 'Larson', 'tlarson1@51.la', 'Female', '207.108.96.210', 91011],
           [3, 'Walter', 'Kennedy', 'wkennedy2@baidu.com', 'Male', '199.147.223.56', 50114],
           [4, 'Andrea', 'Richards', 'arichards3@google.nl', 'Female', '230.195.124.95', 76489],
           [5, 'Carol', 'Jones', 'cjones4@elegantthemes.com', 'Female', '250.197.111.90', 56501],
           [6, 'Alice', 'Freeman', 'afreeman5@elegantthemes.com', 'Female', '52.195.252.131', 77170],
           [7, 'Gerald', 'Fisher', 'gfisher6@slashdot.org', 'Male', '81.2.22.62', 75625],....]

Если нам нужно отсортировать указанные выше данные массива из коробки, то мы можем установить порядок сортировки в массиве, используя синтаксис;

 $qTable[$index]=$sort_order;
E.g. $qTable=[1=>'asc',4=>'desc',3=>'asc'];

Это означает сортировку столбца 1 ASC, столбца 4 DESC, затем столбца 3 ASC. Затем мы можем использовать функцию ниже для сортировки данных нашей многомерной базы данных;

   function sortMulti($data, $orders)
    {
        $args = [];
        foreach ($data as $key => $row) {
            foreach ($orders as $index => $order) {
                if (!isset($row[$index])) continue; //Ignore if column does'nt exist
                $args[$index]['d'][$key] = $row[$index]; //Get all values within the column
                $args[$index]['o']       = 'desc' == strtolower($order) ? SORT_DESC : SORT_ASC; //Get the Sort order 'ASC' is the default
            }
        }
        $p = [];
//Below we need to organize our entries as arguments for array_multisort
        foreach ($args as $arg) {
            $p[] = $arg['d'];
            $p[] = $arg['o'];
//Below we need to check if column contains only numeric or not.
//If all values are numeric, then we use numeric sort flag, otherwise NATURAL
//Manipulate for more conditions supported
            $p[] = count($arg['d']) == count(array_filter($arg['d'], 'is_numeric')) ? SORT_NUMERIC : SORT_NATURAL;
        }
        $p[] = &$data; //Pass by reference
        call_user_func_array('array_multisort', $p); //Call Php's own multisort with parameters in required order.
        return $data; //Our final array sorted.
    }

Тогда мы можем использовать его, как показано ниже;

$data=[[...],[...],...];
$order=[1=>'asc',4=>'desc',3=>'asc'];

$sorted=sortMulti($data,$order);

Для данных массива значений ключей E.g. $data=[['c1'=>1212,'c2'=>'mynames'],...]; Используйте заказ как $order=['c1'=>'desc','c10'=>'asc'];

Я протестировал вышеупомянутое с массивом из 1000 записей. Надеюсь, это кому-нибудь поможет.

1 голос
/ 11 марта 2010

Вы можете использовать функцию usort с обратным вызовом

http://www.php.net/manual/en/function.usort.php

0 голосов
/ 01 декабря 2017

Вы можете создать функцию самостоятельно, как показано ниже

частная функция orderArrayBycolumn ($ array, $ column) {

    $newArray = [];
    foreach ($array as $key => $value) {
        $newArray[$value[$column]] = $value;
    }

    $array = [];

    ksort($newArray);

    foreach ($newArray as $key => $value) {
        $array[] = $value;
    }      

    return $array;
}
0 голосов
/ 18 июля 2017

Альтернативой usort является создание массива, который индексирует массив, который вы хотите отсортировать, и индексируется данными, по которым вы хотите отсортировать.

В следующем фрагменте, $ customAttributes - это массив объектов, которые я хотел бы отсортировать по name .Сначала создается $ sort , индексируемый name и содержащий индекс массива соответствующего $ customAttributes элемента.

$sort = [];
foreach( $customAttributes as $c => $ca )
{
    $sort[$ca->name] = $c;
}

ksort затем используется для сортировки массива по ключу.

ksort( $sort );

После сортировки массива $ sort выполните итерацию по нему и создайте упорядоченный $ массив.

$ordered = [];
foreach( $sort as $s )
{
    $ordered[] = $customAttributes[$s];
}

Мне нравится это решение, потому что вызовов функций меньше, чем с использованием обратных вызовов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...