Сортировать массив объектов по полям объекта

430

Как я могу отсортировать этот массив объектов одним из своих полей, например name или count?

  Array
(
    [0] => stdClass Object
        (
            [ID] => 1
            [name] => Mary Jane
            [count] => 420
        )

    [1] => stdClass Object
        (
            [ID] => 2
            [name] => Johnny
            [count] => 234
        )

    [2] => stdClass Object
        (
            [ID] => 3
            [name] => Kathy
            [count] => 4354
        )

   ....
Теги:
object
arrays
sorting

16 ответов

571
Лучший ответ

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

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

usort($your_data, "cmp");

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

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

usort($your_data, array($this, "cmp"))
  • 83
    Это замечательно, но если функция сортировки находится в том же классе, что и вызывающая функция, вы должны использовать: usort ($ your_data, array ($ this, "cmp"));
  • 5
    @rmooney Да, но только если ты в классе.
Показать ещё 4 комментария
401

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

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

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

  • 14
    Мне нравится этот ответ лучше, чем принятый ответ, поскольку мы можем быстро определить функцию сравнения и использовать ее в классе.
  • 0
    Это сработало для меня, однако принятый ответ - нет. Класс не будет распознавать функцию обратного вызова по имени. Я не уверен почему. Спасибо
Показать ещё 10 комментариев
37

если вы используете 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')); 
22
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, откуда вы взяли этот массив? Надеюсь, что не из базы данных?

  • 0
    На самом деле, $result будет содержать TRUE если он успешен, и ваше сравнение должно быть $a->name > $b->name . :)
  • 1
    @ cambraca: о, забыл, что принимает массив по ссылке. Кстати, ОП не сказал, в каком порядке ему нужно сортировать коллекцию.
Показать ещё 13 комментариев
21

Если вы хотите отсортировать целочисленные значения:

// Desc sort
usort($array,function($first,$second){
    return $first->number < $second->number;
});

// Asc sort
usort($array,function($first,$second){
    return $first->number > $second->number;
});

ОБНОВЛЕНО со строкой, не забудьте преобразовать в тот же регистр (верхний или нижний)

// Desc sort
usort($array,function($first,$second){
    return strtolower($first->text) < strtolower($second->text);
});

// Asc sort
usort($array,function($first,$second){
    return strtolower($first->text) > strtolower($second->text);
});
8

Вы можете использовать эту функцию (работает в версии 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)
  • 0
    Я использовал $a->{$key} и $b->{$key} а не $a[$key] и $b[$key] как мы, строго говоря, имеем дело со свойствами, а не с элементами массива, но это был все еще ответ, который я искал.
  • 0
    Пожалуйста, реализуйте предложение @ SteJ в примере кода, так как решение, которое вы даете, работает только для простых объектов, но с исправлением SteJ оно работает для всех массивов объектов, на которых я пробовал
3

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

usort($array,function($first,$second){
    return strcmp($first->name, $second->name);
});
2

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

$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

Нижняя сторона всех ответов здесь заключается в том, что они используют имена полей статические, поэтому я написал скорректированную версию в стиле ООП. Предположим, что вы используете методы 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;
    }
} 
1

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

$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

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

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

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

  • 0
    Насколько конкретно этот Codeigniter специфичен?
1

Если вам требуется локальное сравнение строк, вы можете использовать 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);
  });
0

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

   usort($threads,function($first,$second){
        return strtotime($first->dateandtime) < strtotime($second->dateandtime);
    });
0

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

usort($listable_products, function($a, $b) {
    global $translator;
    return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});
0

Вы можете использовать sorted функцию 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
    Пожалуйста, объясните, почему OP потребуется целая дополнительная библиотека, чтобы обеспечить средство, казалось бы, разрешаемое встроенными функциями
0

Если вам нужно отсортировать только по одному полю, то usort - хороший выбор. Однако решение быстро становится беспорядочным, если вам нужно сортировать по нескольким полям. В этом случае можно использовать YaLinqo library *, которая реализует 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() в конце, если вам это нужно.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню