Массив сортировки PHP по значению подмассива

111

У меня следующая структура массива:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )

Как лучше всего упорядочить массив поэтапно на основе optionNumber?

Итак, результаты выглядят так:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )
Sjwdavies
источник

Ответы:

205

Используйте usort.

function cmp_by_optionNumber($a, $b) {
  return $a["optionNumber"] - $b["optionNumber"];
}

...

usort($array, "cmp_by_optionNumber");

В PHP ≥5.3 вместо этого следует использовать анонимную функцию :

usort($array, function ($a, $b) {
    return $a['optionNumber'] - $b['optionNumber'];
});

Обратите внимание, что оба приведенных выше кода предполагают $a['optionNumber']целое число. Используйте @St. Решение Джона Джонсона, если это строки.


В PHP ≥7.0 используйте оператор космического корабля<=> вместо вычитания, чтобы предотвратить проблемы переполнения / усечения.

usort($array, function ($a, $b) {
    return $a['optionNumber'] <=> $b['optionNumber'];
});
Kennytm
источник
1
На самом деле это не помогает мне, поскольку usort требует, чтобы я предоставил ему функцию для использования - это сложный момент, который я не могу понять
Sjwdavies
17
Ну, он просто дал вам функцию. И вам придется согласиться с тем, что не всегда есть встроенная функция, позволяющая делать то, что вы хотите, вы должны написать ее самостоятельно. Функции сравнения просто требуют возврата 1, 0 или -1, указывающих порядок сортировки для двух элементов.
Tesserex
1
Я посмотрел дальше в usort, и это действительно здорово. Я написал простую функцию сравнения с приведенной выше, но пропустил '=='. Спасибо за помощь, ребята
Sjwdavies
3
Теперь также в качестве закрытия: - usort ($ array, function ($ a, $ b) {return $ b ["optionNumber"] - $ a ["optionNumber"];});
Joeri
1
@ KiloumapL'artélon Если результат есть < 0, он сообщает функции сортировки, которая aдолжна появиться раньше b. Если это так, > 0то bдолжно появиться раньше a.
kennytm
57

Использовать usort

 usort($array, 'sortByOption');
 function sortByOption($a, $b) {
   return strcmp($a['optionNumber'], $b['optionNumber']);
 }
Сент-Джон Джонсон
источник
7
@BenSinclair, это потому, что решение Кенни для чисел, это решение для строк. Оба они верны :-) +1 за эту альтернативу.
kubilay
Для сортировки без учета регистра используйте strcasecmp вместо strcmp
user570605 02
можем ли мы определить ключ для второго порядка в массиве, означает, что сначала мы выполняем сортировку с помощью optionNumber, а затем сортировку с помощью lastUpdated. Как это сделать?
Bhavin Thummar
16

Я использовал оба решения Kenny TM и AJ Quick и придумал функцию, которая может помочь в решении этой проблемы во многих случаях, например, при использовании сортировки ASC или DESC или сохранения ключей или если у вас есть объекты как дочерние элементы массива .

Вот эта функция (работает для PHP7 и выше из-за оператора космического корабля):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if ($preserveKeys) {
        $c = [];
        if (is_object(reset($array))) {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v->$value);
            }
        } else {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v[$value]);
            }
        }
        $asc ? asort($b) : arsort($b);
        foreach ($b as $k => $v) {
            $c[$k] = $array[$k];
        }
        $array = $c;
    } else {
        if (is_object(reset($array))) {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
            });
        } else {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
            });
        }
    }

    return $array;
}

Использование:

sortBySubValue($array, 'optionNumber', true, false);

редактировать

Первую часть можно переписать с помощью, uasort()а функция будет короче (работает для PHP7 и выше из-за оператора космического корабля):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if (is_object(reset($array))) {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        });
    } else {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        });
    }
    return $array;
}
Пигалев Павел
источник
Это лучший и самый полезный ответ здесь, он должен быть наверху;)
Эди Будимилич
@EdiBudimilic спасибо, я ценю это! Кстати, я обновил свой ответ и добавил более короткую версию этой функции :)
Пигалев Павел
1
Для того, чтобы сделать эту работу для меня, я должен был использовать >(больше) вместо -(минуса) при сравнении $aи $bзначения , так как я сравнение строк. Хотя все еще работает.
Джеймс
1
@ Джеймс, ты прав. Я изменил ответ и добавил использование оператора космического корабля (<=>). Теперь все должно работать нормально.
Пигалев Павел
Есть ли способ сделать этот регистр нечувствительным?
loeffel
4

Ключи удаляются при использовании функции, подобной приведенной выше. Если ключи важны, следующая функция будет поддерживать их ... но циклы foreach довольно неэффективны.

function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[$key] = $a[$key];
    }
    return $c;
}
$array = subval_sort($array,'optionNumber');

Используйте arsort вместо asort, если хотите от большего к меньшему.

Код кредита: http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/

Эй Джей Квик
источник
4

Использование array_multisort (), array_map ()

array_multisort(array_map(function($element) {
      return $element['optionNumber'];
  }, $array), SORT_ASC, $array);

print_r($array);

ДЕМО

Ганшьям Накия
источник
2
Это просто работает очень легко. Спасибо. Все, что мне нужно было сделать, это изменить имя столбца, и это сработало.
Kobus Myburgh
2
Это также сохраняет ключи для родительского массива
JonnyS
3

PHP 5.3+

usort($array, function($a,$b){ return $a['optionNumber']-$b['optionNumber'];} );
Самер Ата
источник