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
)
....
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.
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)
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;
}
}
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 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 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.
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 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);
});
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 usort
, like this:
usort($array,function($first,$second){
return strcmp($first->name, $second->name);
});
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'));
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");
$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'));
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.
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;
}
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");
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
if you want to sort dates
usort($threads,function($first,$second){
return strtotime($first->dateandtime) < strtotime($second->dateandtime);
});
Source: Stackoverflow.com