Сортировка массива объектов по полям объектов
как я могу отсортировать этот массив объектов по одному из его полей, например 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
)
....
17 ответов:
использовать usort, вот пример, адаптированный из руководства:
function cmp($a, $b) { return strcmp($a->name, $b->name); } usort($your_data, "cmp");
изменения, импортированные из комментариев:
Если вы сортируете массив внутри класса, и ваша функция сортировки
cmpтакже определяется внутри класса, затем используйте это:usort($your_data, array($this, "cmp"))
вот более подходящий способ с помощью замыканий
usort($your_data, function($a, $b) { return strcmp($a->name, $b->name); });обратите внимание, что это не в документации PHP, но если вы используете 5.3+ closures поддерживаются, где могут быть предоставлены вызываемые аргументы.
Если вы используете php ООП вам может потребоваться изменить:
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'));
usort($array, 'my_sort_function'); var_dump($array); function my_sort_function($a, $b) { return $a->name < $b->name; }тот же код будет с
Если вы хотите отсортировать целые значения:
// 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); });
Вы можете использовать эту функцию (работает в 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)
можно использовать
usort, например:usort($array,function($first,$second){ return strcmp($first->name, $second->name); });
недостатком всех ответов здесь является то, что они используют статический имена полей, поэтому я написал скорректированную версию в стиле ООП. Предполагается, что вы используете методы 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; } }
Если все не удается здесь есть другое решение:
$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;
Если вам нужно локальное сравнение строк, вы можете использовать
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); });
Если вы используете это внутри Codeigniter, вы можете использовать методы:
usort($jobs, array($this->job_model, "sortJobs")); // function inside Model usort($jobs, array($this, "sortJobs")); // Written inside Controller.@rmooney спасибо за предложение. Это действительно помогает мне.
Спасибо за вдохновение, мне также пришлось добавить внешний параметр $ translator
usort($listable_products, function($a, $b) { global $translator; return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator)); });
простая альтернатива, которая позволяет динамически определять поле, на котором основана сортировка:
$order_by = 'name'; usort($your_data, function ($a, $b) use ($order_by) { return strcmp($a->{$order_by}, $b->{$order_by}); });это основано на закрытие класс, что позволяет анонимные функции. Он доступен с PHP 5.3.
если вам нужно отсортировать только по одному полю, то
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()в конце концов, если вам это нужно.* я
можно использовать отсортированный С 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'));
Если вы хотите отсортировать нужные
usort($threads,function($first,$second){ return strtotime($first->dateandtime) < strtotime($second->dateandtime); });
это то, что у меня есть для служебного класса
class Util { public static function sortArrayByName(&$arrayToSort, $meta) { usort($arrayToSort, function($a, $b) use ($meta) { return strcmp($a[$meta], $b[$meta]); }); } }называем это:
Util::sortArrayByName($array, "array_property_name");
Comments