PHP сортирует массив объектов по ключу в пользовательский заказ, т.е. 1,2,3 в 2,1,3 [дубликат]

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

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

422
задан Alex 24 September 2014 в 11:36
поделиться

17 ответов

Используйте usort , вот пример, адаптированный из руководства:

function cmp($a, $b)
{
    return strcmp($a->name, $b->name);
}

usort($your_data, "cmp");

редактирует импортированные из комментариев:

Если вы сортируете массив изнутри класса, и ваша функция сортировки cmp также определена внутри класса, тогда используйте это:

usort($your_data, array($this, "cmp"))
544
ответ дан jrharshath 19 August 2018 в 16:34
поделиться
  • 1
    Это здорово, но если функция сортировки находится в том же классе, что и вызывающая функция, вы должны использовать: usort ($ your_data, array ($ this, & quot; cmp & quot;)); – rmooney 20 September 2013 в 21:53
  • 2
    @rmooney Да, но только если вы находитесь внутри класса. – cambraca 20 September 2013 в 23:37
  • 3
    положите первый комментарий @rmooney в свой ответ – Mohammad Faisal 18 February 2014 в 14:57
  • 4
    Или, если ваша функция сравнения находится в вашей модели / объекте, который вы сравниваете (это, по-моему, более чистый дизайн), вы должны включить полное пространство имен в вашу модель / объект следующим образом: uasort ($ members, array ("Path \ to \ your \ Model \ Member & quot ;, "compareByName")); – clauziere 4 April 2014 в 20:04
  • 5
    это не возвращает мне ничего не отсортированного, просто самый большой первый, и все остальное я unsort – Alberto Acuña 22 October 2016 в 12:21

Если все это не удается, это другое решение:

$names = array(); 
foreach ($my_array as $my_object) {
    $names[] = $my_object->name; //any object field
}

array_multisort($names, SORT_ASC, $my_array);

return $my_array;
2
ответ дан Adrian P. 19 August 2018 в 16:34
поделиться

, если вы используете php oop, вам может потребоваться изменить:

public static function cmp($a, $b) 
{
    return strcmp($a->name, $b->name);
}

//in this case FUNCTION_NAME would be cmp
usort($your_data, array('YOUR_CLASS_NAME','FUNCTION_NAME')); 
38
ответ дан Andy 19 August 2018 в 16:34
поделиться

Если вам нужно отсортировать только одно поле, тогда usort - хороший выбор. Однако решение быстро становится беспорядочным, если вам нужно сортировать по нескольким полям. В этом случае можно использовать библиотеку YaLinqo *, которая реализует синтаксис SQL-подобных запросов для массивов и объектов. Он имеет довольно синтаксис для всех случаев:

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

Здесь '$v->count' является сокращением для function ($v) { return $v->count; } (либо можно использовать). Эти цепочки методов возвращают итераторы, но вы можете получить массивы, добавив ->toArray() в конце, если вам это нужно.

*, разработанный мной

0
ответ дан Athari 19 August 2018 в 16:34
поделиться

Простая альтернатива, позволяющая динамически определять поле, на котором основана сортировка:

$order_by = 'name';
usort($your_data, function ($a, $b) use ($order_by)
{
    return strcmp($a->{$order_by}, $b->{$order_by});
});

Это основано на классе Closure , который позволяет анонимные функции , Он доступен с PHP 5.3.

1
ответ дан clami219 19 August 2018 в 16:34
поделиться

Суть всех ответов здесь в том, что они используют имена статических полей, поэтому я написал скорректированную версию в стиле ООП. Предположим, вы используете методы getter, которые вы можете использовать непосредственно в этом классе и использовать имя поля в качестве параметра. Возможно, кто-то сочтет это полезным.

class CustomSort{

    public $field = '';

    public function cmp($a, $b)
    {
        /**
         * field for order is in a class variable $field
         * using getter function with naming convention getVariable() we set first letter to uppercase
         * we use variable variable names - $a->{'varName'} would directly access a field
         */
        return strcmp($a->{'get'.ucfirst($this->field)}(), $b->{'get'.ucfirst($this->field)}());
    }

    public function sortObjectArrayByField($array, $field)
    {
        $this->field = $field;
        usort($array, array("Your\Namespace\CustomSort", "cmp"));;
        return $array;
    }
} 
2
ответ дан Horst Jahns 19 August 2018 в 16:34
поделиться

Если вы используете это внутри Codeigniter, вы можете использовать методы:

usort($jobs, array($this->job_model, "sortJobs"));  // function inside Model
usort($jobs, array($this, "sortJobs")); // Written inside Controller.

@rmooney спасибо за предложение. Это действительно помогает мне.

1
ответ дан Muhammad Raheel 19 August 2018 в 16:34
поделиться

Вы можете использовать эту функцию (работает в версии PHP> = 5.3):

function sortArrayByKey(&$array,$key,$string = false,$asc = true){
    if($string){
        usort($array,function ($a, $b) use(&$key,&$asc)
        {
            if($asc)    return strcmp(strtolower($a{$key}), strtolower($b{$key}));
            else        return strcmp(strtolower($b{$key}), strtolower($a{$key}));
        });
    }else{
        usort($array,function ($a, $b) use(&$key,&$asc)
        {
            if($a[$key] == $b{$key}){return 0;}
            if($asc) return ($a{$key} < $b{$key}) ? -1 : 1;
            else     return ($a{$key} > $b{$key}) ? -1 : 1;

        });
    }
}

Пример:

sortArrayByKey($yourArray,"name",true); //String sort (ascending order)
sortArrayByKey($yourArray,"name",true,false); //String sort (descending order)
sortArrayByKey($yourArray,"id"); //number sort (ascending order)
sortArrayByKey($yourArray,"count",false,false); //number sort (descending order)
8
ответ дан PoengAlex 19 August 2018 в 16:34
поделиться
  • 1
    Я использовал $a->{$key} и $b->{$key}, а не $a[$key] и $b[$key], поскольку мы, строго говоря, имеем дело со свойствами, а не с элементами массива, но это был еще тот ответ, который я искал. – SteJ 19 November 2016 в 16:19
  • 2
    Внесите предложение @ SteJ в код примера, поскольку решение, которое вы даете, работает только для простых объектов, но с исправлением SteJ оно работает для всех массивов объектов, которые я пробовал – user2993145 8 June 2017 в 15:22

Вы можете использовать usort, например:

usort($array,function($first,$second){
    return strcmp($first->name, $second->name);
});
22
ответ дан Roman Yakoviv 19 August 2018 в 16:34
поделиться
  • 1
    Это работало лучше, чем принятый для меня ответ. – Robin van Baalen 10 October 2017 в 20:52

Лучше использовать закрытие

usort($your_data, function($a, $b)
{
    return strcmp($a->name, $b->name);
});

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

401
ответ дан Scott Quinlan 19 August 2018 в 16:34
поделиться
  • 1
    Я люблю это лучше, чем принятый ответ, так как мы можем быстро определить функцию сравнения и использовать его в классе – Nam G VU 1 May 2012 в 19:43
  • 2
    @IamJohnGalt - Возможно, это актуально: посмотрите этот комментарий на php.net – Bruno Belotti 28 May 2013 в 23:39
  • 3
    Если вы хотите сохранить ключи массива, используйте uasort() – gillytech 1 May 2015 в 00:36
  • 4
    Для сортировки desc, -1 * strcmp($a->name, $b->name); – Wallace Maxters 14 July 2015 в 13:59
  • 5
    Не нужно умножать сортировку desc. Просто замените аргументы: strcmp($b->name, $a->name) – zxcat 19 March 2016 в 01:53

Если вам требуется локальное сопоставление строк, вы можете использовать strcoll вместо strcmp.

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

  usort($your_data,function($a,$b){
    setlocale (LC_COLLATE, 'pl_PL.UTF-8'); // Example of Polish language collation
    return strcoll($a->name,$b->name);
  });
1
ответ дан Wilq 19 August 2018 в 16:34
поделиться
usort($array, 'my_sort_function');

var_dump($array);

function my_sort_function($a, $b)
{
    return $a->name < $b->name;
}

Тот же код будет с полем count.

Подробнее о usort: http://ru2.php.net/usort

Btw, откуда вы взяли этот массив? Надеюсь, что не из базы данных?

22
ответ дан zerkms 19 August 2018 в 16:34
поделиться
  • 1
    Фактически $result будет содержать TRUE, если он успешный, и ваше сравнение должно быть $a->name > $b->name. :) – cambraca 26 November 2010 в 04:56
  • 2
    @cambraca: О, забыл, что принимает массив по ссылке. Btw, OP не сказал, какой порядок ему нужен для сортировки коллекции. – zerkms 26 November 2010 в 04:57
  • 3
    ну да, это база данных :) фактически из функции, которая получает данные из базы данных – Alex 26 November 2010 в 05:01
  • 4
    @Alex: почему бы вам не отсортировать его в базе данных? ORDER BY count – zerkms 26 November 2010 в 05:02
  • 5
    это сложнее, потому что это часть функции stadard wordpress, и когда я пишу плагин, я не могу изменить wp-файлы. Я попробовал ваш пример с помощью create_function (потому что я использую его внутри класса, и я не знаю, как передать имя функции в usort): create_function('$a,$b', "return $a->count < $b->count;"), но я не могу заставить его работать :( Я получаю несколько уведомлений и предупреждение, что usort ожидает, что параметр 2 будет действительным обратным вызовом – Alex 26 November 2010 в 05:11

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

use function \nspl\a\sorted;
use function \nspl\op\propertyGetter;
use function \nspl\op\methodCaller;

// Sort by property value
$sortedByCount = sorted($objects, propertyGetter('count'));

// Or sort by result of method call
$sortedByName = sorted($objects, methodCaller('getName'));
0
ответ дан Ihor Burlachenko 19 August 2018 в 16:34
поделиться
  • 1
    Пожалуйста, объясните, почему OP понадобится целая дополнительная библиотека, чтобы обеспечить объект, который, по-видимому, разрешен встроенными функциями – ggdx 10 August 2018 в 11:36

Спасибо за вдохновение, мне также пришлось добавить внешний параметр $ переводчика

usort($listable_products, function($a, $b) {
    global $translator;
    return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});
0
ответ дан michalzuber 19 August 2018 в 16:34
поделиться

, если вы хотите отсортировать даты

   usort($threads,function($first,$second){
        return strtotime($first->dateandtime) < strtotime($second->dateandtime);
    });
0
ответ дан Nicolas Giszpenc 19 August 2018 в 16:34
поделиться
0
ответ дан Demodave 31 October 2018 в 03:26
поделиться
24
ответ дан Roman Yakoviv 31 October 2018 в 03:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: