Related
How can I sort this array of objects by one of its fields, like name or 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
)
....
Use usort, here's an example adapted from the manual:
function cmp($a, $b) {
return strcmp($a->name, $b->name);
}
usort($your_data, "cmp");
You can also use any callable as the second argument. Here are some examples:
Using anonymous functions (from PHP 5.3)
usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
From inside a class
usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
Using arrow functions (from PHP 7.4)
usort($your_data, fn($a, $b) => strcmp($a->name, $b->name));
Also, if you're comparing numeric values, fn($a, $b) => $a->count - $b->count as the "compare" function should do the trick, or, if you want yet another way of doing the same thing, starting from PHP 7 you can use the Spaceship operator, like this: fn($a, $b) => $a->count <=> $b->count.
Heres a nicer way using closures
usort($your_data, function($a, $b)
{
return strcmp($a->name, $b->name);
});
Please note this is not in PHP's documentation but if you using 5.3+ closures are supported where callable arguments can be provided.
If you want to sort integer values:
// Desc sort
usort($array,function($first,$second){
return $first->number < $second->number;
});
// Asc sort
usort($array,function($first,$second){
return $first->number > $second->number;
});
UPDATED
with the string don't forget to convert to the same register (upper or lower)
// 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);
});
if you're using php oop you might need to change to:
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;
}
The same code will be with the count field.
More details about usort: http://ru2.php.net/usort
Btw, where did you get that array from? I hope that not from database?
If everything fails here is another solution:
$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;
You can use this function (works in PHP Version >= 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;
});
}
}
Example:
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)
You can use usort, like this:
usort($array,function($first,$second){
return strcmp($first->name, $second->name);
});
if you want to sort dates
usort($threads,function($first,$second){
return strtotime($first->dateandtime) < strtotime($second->dateandtime);
});
To sort on one column of values, a combination of array_column() and array_multisort() is one sensible way. Demo
array_multisort(array_column($array, 'count'), $array);
Or only call upon usort() with the spaceship operator to perform less iterating in this scenario. Demo
usort($array, fn($a, $b) => $a->count <=> $b->count);
Notice that although the count values are cast as string type values in the input array, both sorting functions will correctly sort the values numerically instead of alphabetizing them (erroneously putting 23420 before 420). This is a reliable default feature.
Even if you are variably declaring the column to sort on, both approaches allow the variable to be used without any addition techniques.
Multisort Demo with variable
$property = 'count';
array_multisort(array_column($array, $property), $array);
Usort Demo with variable
$property = 'count';
usort($array, fn($a, $b) => $a->$property <=> $b->$property);
Both native sorting functions modify by reference, so do not try to access the sorted array by their return value.
array_multisort()'s default sorting direction is ascending, so it is of no benefit to explicitly use the SORT_ASC between the two array parameters. If descending sorting is desired, write SORT_DESC between the two arrays (as the second parameter).
usort() will sort ascending when the custom function body puts $a data on the left side of the spaceship operator and $b data on the right side. For sorting in a descending direction, just write $b data on the left and $a data on the right.
Both approaches are capable of receiving multiple sorting rules, but because this question only asks to sort on a single column, that guidance is inappropriate here.
It will be less efficient to call a function (like strcmp()) on every iteration while sorting. This is no longer best practice. Neither is using a two-way comparison (like > or <) to return a boolean outcome. A three-way comparison is expected from usort().
For sorting data with multiple rules/columns/properties, this answer gives good guidance.
Downside of all answers here is that they use static field names, so I wrote an adjusted version in OOP style. Assumed you are using getter methods you could directly use this Class and use the field name as parameter. Probably someone find it useful.
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;
}
}
If you need local based string comparison, you can use strcoll instead of strcmp.
Remeber to first use setlocale with LC_COLLATE to set locale information if needed.
usort($your_data,function($a,$b){
setlocale (LC_COLLATE, 'pl_PL.UTF-8'); // Example of Polish language collation
return strcoll($a->name,$b->name);
});
A simple alternative that allows you to determine dynamically the field on which the sorting is based:
$order_by = 'name';
usort($your_data, function ($a, $b) use ($order_by)
{
return strcmp($a->{$order_by}, $b->{$order_by});
});
This is based on the Closure class, which allows anonymous functions. It is available since PHP 5.3.
If you are using this inside Codeigniter, you can use the methods:
usort($jobs, array($this->job_model, "sortJobs")); // function inside Model
usort($jobs, array($this, "sortJobs")); // Written inside Controller.
#rmooney thank you for the suggestion. It really helps me.
Thanks for the inspirations, I also had to add an external $translator parameter
usort($listable_products, function($a, $b) {
global $translator;
return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});
If you need to sort by only one field, then usort is a good choice. However, the solution quickly becomes messy if you need to sort by multiple fields. In this case, YaLinqo library* can be used, which implements SQL-like query syntax for arrays and objects. It has a pretty syntax for all cases:
$sortedByName = from($objects)->orderBy('$v->name');
$sortedByCount = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');
Here, '$v->count' is a shorthand for function ($v) { return $v->count; } (either can be used). These method chains return iterators, but you can get arrays by adding ->toArray() in the end if you need it.
* developed by me
You can use sorted function from 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'));
This is what I have for a utility class
class Util
{
public static function sortArrayByName(&$arrayToSort, $meta) {
usort($arrayToSort, function($a, $b) use ($meta) {
return strcmp($a[$meta], $b[$meta]);
});
}
}
Call it:
Util::sortArrayByName($array, "array_property_name");
You can use usort like this
If you want to sort by number:
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
Or Abc char:
function cmp($a, $b)
{
return strcmp($a["fruit"], $b["fruit"]);
}
$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";
usort($fruits, "cmp");
See more: https://www.php.net/manual/en/function.usort.php
$array[0] = array('key_a' => 'z', 'key_b' => 'c');
$array[1] = array('key_a' => 'x', 'key_b' => 'b');
$array[2] = array('key_a' => 'y', 'key_b' => 'a');
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('key_b'));
reference answer of Demodave to eating multi key
function array_sort_by(array $arr, $keys){
if(!is_array($keys))
$keyList = explode(',', $keys);
$keyList = array_keys(array_flip($keyList)); // array_unique
$keyList = array_reverse($keyList);
$result = &$arr;
foreach ($keyList as $key) {
if(array_key_exists($key, $arr))
$result = usort($result, function($a, $b) use ($key) { return strcmp($a->{$key}, $b->{$key}); });
}
return $result;
}
use this....
$array_list = [
"Apple" => 2,
"Pear" => 1,
"Orange" => 5,
"Lemon" => 1,
"Strawberry" => 2,
"Banana" => 3
];
function cmp($a, $b) {
return $b - $a;
}
$ao = new ArrayObject($object);
$ao->uasort('cmp');
print_r(json_encode($ao));
Bye!!!!
For my part, here is how I proceeded to sort an array of objects by object fields:
Code: (Demo) -- sorts by last_name ASC, then first_name ASC
<?php
$array = array(
(object)array(
'first_name' => 'Léa',
'last_name' => 'Weber',
),
(object)array(
'first_name' => 'Alexandre',
'last_name' => 'Dupont',
),
(object)array(
'first_name' => 'Léa',
'last_name' => 'Zotal',
),
(object)array(
'first_name' => 'Jérémie',
'last_name' => 'Hoffmann',
)
);
usort($array, function($a, $b) {
return [$a->last_name, $a->first_name]
<=>
[$b->last_name, $b->first_name];
});
var_export($array);
Outpout:
array (
0 =>
(object) array(
'first_name' => 'Alexandre',
'last_name' => 'Dupont',
),
1 =>
(object) array(
'first_name' => 'Jérémie',
'last_name' => 'Hoffmann',
),
2 =>
(object) array(
'first_name' => 'Léa',
'last_name' => 'Weber',
),
3 =>
(object) array(
'first_name' => 'Léa',
'last_name' => 'Zotal',
),
)
Arrow syntax with PHP7.4 and higher.
Makes sorting by multiple columns SUPER easy with the spaceship operator (<=>) aka the "Combined Comparison Operator" or "Three-way Comparison Operator".
Resource: https://wiki.php.net/rfc/combined-comparison-operator
https://stackoverflow.com/a/54647220/18090932
How can I sort this array of objects by one of its fields, like name or 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
)
....
Use usort, here's an example adapted from the manual:
function cmp($a, $b) {
return strcmp($a->name, $b->name);
}
usort($your_data, "cmp");
You can also use any callable as the second argument. Here are some examples:
Using anonymous functions (from PHP 5.3)
usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
From inside a class
usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
Using arrow functions (from PHP 7.4)
usort($your_data, fn($a, $b) => strcmp($a->name, $b->name));
Also, if you're comparing numeric values, fn($a, $b) => $a->count - $b->count as the "compare" function should do the trick, or, if you want yet another way of doing the same thing, starting from PHP 7 you can use the Spaceship operator, like this: fn($a, $b) => $a->count <=> $b->count.
Heres a nicer way using closures
usort($your_data, function($a, $b)
{
return strcmp($a->name, $b->name);
});
Please note this is not in PHP's documentation but if you using 5.3+ closures are supported where callable arguments can be provided.
If you want to sort integer values:
// Desc sort
usort($array,function($first,$second){
return $first->number < $second->number;
});
// Asc sort
usort($array,function($first,$second){
return $first->number > $second->number;
});
UPDATED
with the string don't forget to convert to the same register (upper or lower)
// 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);
});
if you're using php oop you might need to change to:
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;
}
The same code will be with the count field.
More details about usort: http://ru2.php.net/usort
Btw, where did you get that array from? I hope that not from database?
If everything fails here is another solution:
$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;
You can use this function (works in PHP Version >= 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;
});
}
}
Example:
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)
You can use usort, like this:
usort($array,function($first,$second){
return strcmp($first->name, $second->name);
});
if you want to sort dates
usort($threads,function($first,$second){
return strtotime($first->dateandtime) < strtotime($second->dateandtime);
});
To sort on one column of values, a combination of array_column() and array_multisort() is one sensible way. Demo
array_multisort(array_column($array, 'count'), $array);
Or only call upon usort() with the spaceship operator to perform less iterating in this scenario. Demo
usort($array, fn($a, $b) => $a->count <=> $b->count);
Notice that although the count values are cast as string type values in the input array, both sorting functions will correctly sort the values numerically instead of alphabetizing them (erroneously putting 23420 before 420). This is a reliable default feature.
Even if you are variably declaring the column to sort on, both approaches allow the variable to be used without any addition techniques.
Multisort Demo with variable
$property = 'count';
array_multisort(array_column($array, $property), $array);
Usort Demo with variable
$property = 'count';
usort($array, fn($a, $b) => $a->$property <=> $b->$property);
Both native sorting functions modify by reference, so do not try to access the sorted array by their return value.
array_multisort()'s default sorting direction is ascending, so it is of no benefit to explicitly use the SORT_ASC between the two array parameters. If descending sorting is desired, write SORT_DESC between the two arrays (as the second parameter).
usort() will sort ascending when the custom function body puts $a data on the left side of the spaceship operator and $b data on the right side. For sorting in a descending direction, just write $b data on the left and $a data on the right.
Both approaches are capable of receiving multiple sorting rules, but because this question only asks to sort on a single column, that guidance is inappropriate here.
It will be less efficient to call a function (like strcmp()) on every iteration while sorting. This is no longer best practice. Neither is using a two-way comparison (like > or <) to return a boolean outcome. A three-way comparison is expected from usort().
For sorting data with multiple rules/columns/properties, this answer gives good guidance.
Downside of all answers here is that they use static field names, so I wrote an adjusted version in OOP style. Assumed you are using getter methods you could directly use this Class and use the field name as parameter. Probably someone find it useful.
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;
}
}
If you need local based string comparison, you can use strcoll instead of strcmp.
Remeber to first use setlocale with LC_COLLATE to set locale information if needed.
usort($your_data,function($a,$b){
setlocale (LC_COLLATE, 'pl_PL.UTF-8'); // Example of Polish language collation
return strcoll($a->name,$b->name);
});
A simple alternative that allows you to determine dynamically the field on which the sorting is based:
$order_by = 'name';
usort($your_data, function ($a, $b) use ($order_by)
{
return strcmp($a->{$order_by}, $b->{$order_by});
});
This is based on the Closure class, which allows anonymous functions. It is available since PHP 5.3.
If you are using this inside Codeigniter, you can use the methods:
usort($jobs, array($this->job_model, "sortJobs")); // function inside Model
usort($jobs, array($this, "sortJobs")); // Written inside Controller.
#rmooney thank you for the suggestion. It really helps me.
Thanks for the inspirations, I also had to add an external $translator parameter
usort($listable_products, function($a, $b) {
global $translator;
return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});
If you need to sort by only one field, then usort is a good choice. However, the solution quickly becomes messy if you need to sort by multiple fields. In this case, YaLinqo library* can be used, which implements SQL-like query syntax for arrays and objects. It has a pretty syntax for all cases:
$sortedByName = from($objects)->orderBy('$v->name');
$sortedByCount = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');
Here, '$v->count' is a shorthand for function ($v) { return $v->count; } (either can be used). These method chains return iterators, but you can get arrays by adding ->toArray() in the end if you need it.
* developed by me
You can use sorted function from 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'));
This is what I have for a utility class
class Util
{
public static function sortArrayByName(&$arrayToSort, $meta) {
usort($arrayToSort, function($a, $b) use ($meta) {
return strcmp($a[$meta], $b[$meta]);
});
}
}
Call it:
Util::sortArrayByName($array, "array_property_name");
You can use usort like this
If you want to sort by number:
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
Or Abc char:
function cmp($a, $b)
{
return strcmp($a["fruit"], $b["fruit"]);
}
$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";
usort($fruits, "cmp");
See more: https://www.php.net/manual/en/function.usort.php
$array[0] = array('key_a' => 'z', 'key_b' => 'c');
$array[1] = array('key_a' => 'x', 'key_b' => 'b');
$array[2] = array('key_a' => 'y', 'key_b' => 'a');
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('key_b'));
reference answer of Demodave to eating multi key
function array_sort_by(array $arr, $keys){
if(!is_array($keys))
$keyList = explode(',', $keys);
$keyList = array_keys(array_flip($keyList)); // array_unique
$keyList = array_reverse($keyList);
$result = &$arr;
foreach ($keyList as $key) {
if(array_key_exists($key, $arr))
$result = usort($result, function($a, $b) use ($key) { return strcmp($a->{$key}, $b->{$key}); });
}
return $result;
}
use this....
$array_list = [
"Apple" => 2,
"Pear" => 1,
"Orange" => 5,
"Lemon" => 1,
"Strawberry" => 2,
"Banana" => 3
];
function cmp($a, $b) {
return $b - $a;
}
$ao = new ArrayObject($object);
$ao->uasort('cmp');
print_r(json_encode($ao));
Bye!!!!
For my part, here is how I proceeded to sort an array of objects by object fields:
Code: (Demo) -- sorts by last_name ASC, then first_name ASC
<?php
$array = array(
(object)array(
'first_name' => 'Léa',
'last_name' => 'Weber',
),
(object)array(
'first_name' => 'Alexandre',
'last_name' => 'Dupont',
),
(object)array(
'first_name' => 'Léa',
'last_name' => 'Zotal',
),
(object)array(
'first_name' => 'Jérémie',
'last_name' => 'Hoffmann',
)
);
usort($array, function($a, $b) {
return [$a->last_name, $a->first_name]
<=>
[$b->last_name, $b->first_name];
});
var_export($array);
Outpout:
array (
0 =>
(object) array(
'first_name' => 'Alexandre',
'last_name' => 'Dupont',
),
1 =>
(object) array(
'first_name' => 'Jérémie',
'last_name' => 'Hoffmann',
),
2 =>
(object) array(
'first_name' => 'Léa',
'last_name' => 'Weber',
),
3 =>
(object) array(
'first_name' => 'Léa',
'last_name' => 'Zotal',
),
)
Arrow syntax with PHP7.4 and higher.
Makes sorting by multiple columns SUPER easy with the spaceship operator (<=>) aka the "Combined Comparison Operator" or "Three-way Comparison Operator".
Resource: https://wiki.php.net/rfc/combined-comparison-operator
https://stackoverflow.com/a/54647220/18090932
Here is my current code to add to the array:
foreach ($query->result() as $exp) {
$activities[] = array('type' => 'level', 'exp' => $exp->exp, 'timestamp' => $badge->timestamp);
}
How would I go about sorting this array according to the value of the 'timestamp' key?
You would need to use usort which will let you sort the array using a user-defined function.
http://www.php.net/manual/en/function.usort.php
Example:
<?php
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
I would use the function array-multisort for the actual sorting, also I would store the values differently:
foreach ($query->result() as $exp) {
$activities[$badge->timestamp] = array('type' => 'level',... );
}
array_multisort($activities, SORT_ASC, $array);
http://php.net/manual/en/function.array-multisort.php
I need to use the uasort() function, but I don't get how to get the arguments in the function... The given example is not so clear for me. How does the cmp function gets his arguments? Someone care to explain?
<?php
// Comparison function
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
// Array to be sorted
$array = array('a' => 4, 'b' => 8, 'c' => -1, 'd' => -9, 'e' => 2, 'f' => 5, 'g' => 3, 'h' => -4);
print_r($array);
// Sort and print the resulting array
uasort($array, 'cmp');
print_r($array);
?>
The order in which elements are picked from the array shouldn't make any difference to the way in which your comparison function works.
uasort will be applied until every element in your array is sorted based upon the comparison you apply to it in your cmp function.
Updated
If you really want to know how it's sorted, looking at the PHP source, the array first has zend_hash_sort applied to it which uses the zend_qsort comparison function which as far as I'm aware, just orders by value.
Try changing your cmp function to the below to see what's going on:
function cmp($a, $b) {
echo "a=$a, b=$b"; // add this to see what's going on
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
How can I sort this array of objects by one of its fields, like name or 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
)
....
Use usort, here's an example adapted from the manual:
function cmp($a, $b) {
return strcmp($a->name, $b->name);
}
usort($your_data, "cmp");
You can also use any callable as the second argument. Here are some examples:
Using anonymous functions (from PHP 5.3)
usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
From inside a class
usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
Using arrow functions (from PHP 7.4)
usort($your_data, fn($a, $b) => strcmp($a->name, $b->name));
Also, if you're comparing numeric values, fn($a, $b) => $a->count - $b->count as the "compare" function should do the trick, or, if you want yet another way of doing the same thing, starting from PHP 7 you can use the Spaceship operator, like this: fn($a, $b) => $a->count <=> $b->count.
Heres a nicer way using closures
usort($your_data, function($a, $b)
{
return strcmp($a->name, $b->name);
});
Please note this is not in PHP's documentation but if you using 5.3+ closures are supported where callable arguments can be provided.
If you want to sort integer values:
// Desc sort
usort($array,function($first,$second){
return $first->number < $second->number;
});
// Asc sort
usort($array,function($first,$second){
return $first->number > $second->number;
});
UPDATED
with the string don't forget to convert to the same register (upper or lower)
// 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);
});
if you're using php oop you might need to change to:
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;
}
The same code will be with the count field.
More details about usort: http://ru2.php.net/usort
Btw, where did you get that array from? I hope that not from database?
If everything fails here is another solution:
$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;
You can use this function (works in PHP Version >= 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;
});
}
}
Example:
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)
You can use usort, like this:
usort($array,function($first,$second){
return strcmp($first->name, $second->name);
});
if you want to sort dates
usort($threads,function($first,$second){
return strtotime($first->dateandtime) < strtotime($second->dateandtime);
});
To sort on one column of values, a combination of array_column() and array_multisort() is one sensible way. Demo
array_multisort(array_column($array, 'count'), $array);
Or only call upon usort() with the spaceship operator to perform less iterating in this scenario. Demo
usort($array, fn($a, $b) => $a->count <=> $b->count);
Notice that although the count values are cast as string type values in the input array, both sorting functions will correctly sort the values numerically instead of alphabetizing them (erroneously putting 23420 before 420). This is a reliable default feature.
Even if you are variably declaring the column to sort on, both approaches allow the variable to be used without any addition techniques.
Multisort Demo with variable
$property = 'count';
array_multisort(array_column($array, $property), $array);
Usort Demo with variable
$property = 'count';
usort($array, fn($a, $b) => $a->$property <=> $b->$property);
Both native sorting functions modify by reference, so do not try to access the sorted array by their return value.
array_multisort()'s default sorting direction is ascending, so it is of no benefit to explicitly use the SORT_ASC between the two array parameters. If descending sorting is desired, write SORT_DESC between the two arrays (as the second parameter).
usort() will sort ascending when the custom function body puts $a data on the left side of the spaceship operator and $b data on the right side. For sorting in a descending direction, just write $b data on the left and $a data on the right.
Both approaches are capable of receiving multiple sorting rules, but because this question only asks to sort on a single column, that guidance is inappropriate here.
It will be less efficient to call a function (like strcmp()) on every iteration while sorting. This is no longer best practice. Neither is using a two-way comparison (like > or <) to return a boolean outcome. A three-way comparison is expected from usort().
For sorting data with multiple rules/columns/properties, this answer gives good guidance.
Downside of all answers here is that they use static field names, so I wrote an adjusted version in OOP style. Assumed you are using getter methods you could directly use this Class and use the field name as parameter. Probably someone find it useful.
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;
}
}
If you need local based string comparison, you can use strcoll instead of strcmp.
Remeber to first use setlocale with LC_COLLATE to set locale information if needed.
usort($your_data,function($a,$b){
setlocale (LC_COLLATE, 'pl_PL.UTF-8'); // Example of Polish language collation
return strcoll($a->name,$b->name);
});
A simple alternative that allows you to determine dynamically the field on which the sorting is based:
$order_by = 'name';
usort($your_data, function ($a, $b) use ($order_by)
{
return strcmp($a->{$order_by}, $b->{$order_by});
});
This is based on the Closure class, which allows anonymous functions. It is available since PHP 5.3.
If you are using this inside Codeigniter, you can use the methods:
usort($jobs, array($this->job_model, "sortJobs")); // function inside Model
usort($jobs, array($this, "sortJobs")); // Written inside Controller.
#rmooney thank you for the suggestion. It really helps me.
Thanks for the inspirations, I also had to add an external $translator parameter
usort($listable_products, function($a, $b) {
global $translator;
return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});
If you need to sort by only one field, then usort is a good choice. However, the solution quickly becomes messy if you need to sort by multiple fields. In this case, YaLinqo library* can be used, which implements SQL-like query syntax for arrays and objects. It has a pretty syntax for all cases:
$sortedByName = from($objects)->orderBy('$v->name');
$sortedByCount = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');
Here, '$v->count' is a shorthand for function ($v) { return $v->count; } (either can be used). These method chains return iterators, but you can get arrays by adding ->toArray() in the end if you need it.
* developed by me
You can use sorted function from 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'));
This is what I have for a utility class
class Util
{
public static function sortArrayByName(&$arrayToSort, $meta) {
usort($arrayToSort, function($a, $b) use ($meta) {
return strcmp($a[$meta], $b[$meta]);
});
}
}
Call it:
Util::sortArrayByName($array, "array_property_name");
You can use usort like this
If you want to sort by number:
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
Or Abc char:
function cmp($a, $b)
{
return strcmp($a["fruit"], $b["fruit"]);
}
$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";
usort($fruits, "cmp");
See more: https://www.php.net/manual/en/function.usort.php
$array[0] = array('key_a' => 'z', 'key_b' => 'c');
$array[1] = array('key_a' => 'x', 'key_b' => 'b');
$array[2] = array('key_a' => 'y', 'key_b' => 'a');
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('key_b'));
reference answer of Demodave to eating multi key
function array_sort_by(array $arr, $keys){
if(!is_array($keys))
$keyList = explode(',', $keys);
$keyList = array_keys(array_flip($keyList)); // array_unique
$keyList = array_reverse($keyList);
$result = &$arr;
foreach ($keyList as $key) {
if(array_key_exists($key, $arr))
$result = usort($result, function($a, $b) use ($key) { return strcmp($a->{$key}, $b->{$key}); });
}
return $result;
}
use this....
$array_list = [
"Apple" => 2,
"Pear" => 1,
"Orange" => 5,
"Lemon" => 1,
"Strawberry" => 2,
"Banana" => 3
];
function cmp($a, $b) {
return $b - $a;
}
$ao = new ArrayObject($object);
$ao->uasort('cmp');
print_r(json_encode($ao));
Bye!!!!
For my part, here is how I proceeded to sort an array of objects by object fields:
Code: (Demo) -- sorts by last_name ASC, then first_name ASC
<?php
$array = array(
(object)array(
'first_name' => 'Léa',
'last_name' => 'Weber',
),
(object)array(
'first_name' => 'Alexandre',
'last_name' => 'Dupont',
),
(object)array(
'first_name' => 'Léa',
'last_name' => 'Zotal',
),
(object)array(
'first_name' => 'Jérémie',
'last_name' => 'Hoffmann',
)
);
usort($array, function($a, $b) {
return [$a->last_name, $a->first_name]
<=>
[$b->last_name, $b->first_name];
});
var_export($array);
Outpout:
array (
0 =>
(object) array(
'first_name' => 'Alexandre',
'last_name' => 'Dupont',
),
1 =>
(object) array(
'first_name' => 'Jérémie',
'last_name' => 'Hoffmann',
),
2 =>
(object) array(
'first_name' => 'Léa',
'last_name' => 'Weber',
),
3 =>
(object) array(
'first_name' => 'Léa',
'last_name' => 'Zotal',
),
)
Arrow syntax with PHP7.4 and higher.
Makes sorting by multiple columns SUPER easy with the spaceship operator (<=>) aka the "Combined Comparison Operator" or "Three-way Comparison Operator".
Resource: https://wiki.php.net/rfc/combined-comparison-operator
https://stackoverflow.com/a/54647220/18090932