首页 > 代码库 > PHP 使用用户自定义的比较函数对数组中的值进行排序
PHP 使用用户自定义的比较函数对数组中的值进行排序
原文:PHP 使用用户自定义的比较函数对数组中的值进行排序
usort
(PHP 4, PHP 5)
usort — 使用用户自定义的比较函数对数组中的值进行排序
说明
&$array
, callable $cmp_function
)本函数将用用户自定义的比较函数对一个数组中的值进行排序。如果要排序的数组需要用一种不寻常的标准进行排序,那么应该使用此函数。
Note:
如果两个成员比较结果相同,则它们在排序后的数组中的顺序未经定义。
Note: 此函数为
array
中的元素赋与新的键名。这将删除原有的键名,而不是仅仅将键名重新排序。
参数
-
array
-
输入的数组
-
cmp_function
-
在第一个参数小于,等于或大于第二个参数时,该比较函数必须相应地返回一个小于,等于或大于 0 的整数。
int callback ( mixed$a
, mixed$b
)CautionReturning non-integer values from the comparison function, such as float, will result in an internal cast to integer of the callback‘s return value. So values such as 0.99 and 0.1 will both be cast to an integer value of 0, which will compare such values as equal.
返回值
成功时返回 TRUE
, 或者在失败时返回 FALSE
。
更新日志
版本 | 说明 |
---|---|
4.1.0 | 引进了新的排序算法。用户自定义函数 cmp_function 将不再保留这些单元的原有顺序。 |
范例
Example #1 usort() 例子
<?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");
foreach ($a as $key => $value)
{ echo "$key: $value\n"; } ?>
以上例程会输出:
0: 11: 22: 33: 54: 6
Note:
很明显在这个小例子中用 sort() 函数更合适。
Example #2 使用多维数组的 usort() 例子
<?php
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");
while (list($key, $value) = each($fruits))
{ echo "$fruits[$key]: " . $value["fruit"] . "\n"; } ?>
当排序多维数组时,$a 和 $b 包含到数组第一个索引的引用。
以上例程会输出:
$fruits[0]: apples$fruits[1]: grapes$fruits[2]: lemons
Example #3 usort() example using a member function of an object
<?php class TestObj { var $name; function TestObj($name) { $this->name = $name; } /* This is the static comparing function: */ static function cmp_obj($a, $b) { $al = strtolower($a->name); $bl = strtolower($b->name); if ($al == $bl) { return 0; } return ($al > $bl) ? +1 : -1; } }$a[] = new TestObj("c"); $a[] = new TestObj("b"); $a[] = new TestObj("d");usort($a, array("TestObj", "cmp_obj"));foreach ($a as $item) { echo $item->name . "\n"; }?>
以上例程会输出:
bcd
Example #4 usort() example using a closure to sort a multi-dimensional array
<?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‘));
foreach ($array as $item)
{ echo $item[‘key_a‘] . ‘, ‘ . $item[‘key_b‘] . "\n"; } ?>
以上例程会输出:
y, ax, bz, c
参见
- uasort() - 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联
- 数组排序函数对比
用户评论:
Hayley Watson (2013-04-08 22:30:19)
As the documentation says, the comparison function needs to return an integer that is either "less than, equal to, or greater than zero". There is no requirement to restrict the value returned to -1, 0, 1.
<?php usort($array, function($a, $b) { if($a->integer_property > $b->integer_property) { return 1; } elseif($a->integer_property < $b->integer_property) { return -1; } else { return 0; } }); ?> can be simplified to
<?php usort($array, function($a, $b) { return $a->integer_property - $b->integer_property; }); ?> This of course applies to any comparison function that calculates an integer "score" for each of its arguments to decide which is "greater".
hexarobi at gmail dot com (2013-02-21 21:04:32)
Needed to sort an array of objects based on multiple properties. (ie: Group, then Last Name, then First Name) Doing this in multiple usorts fails because the second usort ends up shuffling the results of the previous usort because order is undefined when criteria are equal. Ended up writing a function that builds a comparison operator by nesting ternary operators for each field, then using that function in usort(). Hopefully it‘s of use to someone else.
<?php
/*
* Sorts an array of objects by a list of properties.
* Each property can have the following options:
* ‘property‘ can be either a public variable or a method().
* ‘order‘ can be ASC or DESC
* ‘comparer‘ can be string, number, or date
*
* Example:
* sortObjectsByProperties($objects, array(
* array(‘property‘=>‘getPrice()‘, order=>‘ASC‘, ‘comparer‘=>‘number‘),
* array(‘property‘=>‘getName()‘, order=>‘DESC‘, ‘comparer‘=>‘string‘),
* array(‘property‘=>‘created_date‘, order=>‘ASC‘, ‘comparer‘=>‘date‘),
* array(‘property‘=>‘id‘, order=>‘ASC‘, ‘comparer‘=>‘number‘),
* ));
*
* @author Tyler Chamberlain
*/
function sortObjectsByProperties(&$objects, $fields) {
$comparerFunctionString = "";
foreach ($fields as $field) {
if ($field[‘comparer‘] == ‘number‘) {
$comparerFunction = "(\$a->{$field[‘property‘]} == \$b->{$field[‘property‘]} ? 0 : (\$a->{$field[‘property‘]} > \$b->{$field[‘property‘]} ? 1 : -1))";
} elseif ($field[‘comparer‘] == ‘date‘) {
$comparerFunction = "(strtotime(\$a->{$field[‘property‘]}) > strtotime(\$b->{$field[‘property‘]}) ? 1 : -1)";
} else {
$comparerFunction = "strcasecmp(\$a->{$field[‘property‘]},\$b->{$field[‘property‘]})";
}
if ($field[‘order‘] === ‘DESC‘) { $comparerFunction = "-".$comparerFunction; }
$comparerFunctionString .= "$comparerFunction != 0 ? $comparerFunction : (";
}
$comparer = "return ($comparerFunctionString 0 )".str_repeat(")", sizeof($fields)).";";
usort($objects, create_function(‘$a,$b‘, $comparer));
}
?>
Jian Wu (2012-07-06 21:16:20)
The usort function actually moves $b up when the callback function returns both 0 and 1. If you want to preserve the original order in the array, return 1 when $a == $b instead of 0. Try this code below to see how usort alters the order of the original array when all values are the same.
<?php
class TestObj {
private $name;
private $id;
function TestObj($name, $id) {
$this->name = $name;
$this->id = $id;
}
static function cmp_obj($a, $b) {
$al = strtolower($a->name);
$bl = strtolower($b->name);
if ($al == $bl) {
return 0; // return 1 if you don‘t want $b to go in front of $a
}
return ($al > $bl) ? +1 : -1;
}
}
$a[] = new TestObj("a", 1);
$a[] = new TestObj("a", 2);
$a[] = new TestObj("a", 3);
var_dump($a);
usort($a, array("TestObj", "cmp_obj"));
var_dump($a);
?>
zuallauz at gmail dot com (2012-03-29 21:56:45)
When trying to do some custom sorting with objects and an anonymous function it wasn‘t entirely clear how this usort function works. I think it probably uses a quicksort in the background. Basically it actually moves the $b variable up or down in respect to the $a variable. It does NOT move the $a variable inside the callback function. This is key to getting your logic right in the comparisons.
If you return -1 that moves the $b variable down the array, return 1 moves $b up the array and return 0 keeps $b in the same place.
To test I cut down my code to sorting a simple array from highest priority to lowest.
<?php $priorities = array(5, 8, 3, 7, 3);
usort($priorities, function($a, $b) { if ($a == $b) { echo "a ($a) is same priority as b ($b), keeping the same\n"; return 0; } else if ($a > $b) { echo "a ($a) is higher priority than b ($b), moving b down array\n"; return -1; } else { echo "b ($b) is higher priority than a ($a), moving b up array\n"; return 1; } });
echo "Sorted priorities:\n"; var_dump($priorities); ?> Output:
b (8) is higher priority than a (3), moving b up array b (5) is higher priority than a (3), moving b up array b (7) is higher priority than a (3), moving b up array a (3) is same priority as b (3), keeping the same a (8) is higher priority than b (3), moving b down array b (8) is higher priority than a (7), moving b up array b (8) is higher priority than a (5), moving b up array b (8) is higher priority than a (3), moving b up array a (5) is higher priority than b (3), moving b down array a (7) is higher priority than b (5), moving b down array
Sorted priorities: array(5) { [0]=> int(8) [1]=> int(7) [2]=> int(5) [3]=> int(3) [4]=> int(3) }
andi_mclean at ntlworld dot com (2012-02-04 15:58:08)
I needed a sort method that would sort strings but take note of any numbers and would compare them as number. I also want to ignore any non alphanumerical characters.
Eg. Slot 1 Example Slot 10 Example Slot 2 Example
Should infact be Slot 1 Example Slot 2 Example Slot 10 Example
<?php function sort_with_numbers($a , $b) { $a = explode(‘ ‘,$a); $b = explode(‘ ‘,$b); $size = min(count($a), count($b)); for($index =0; $index < $size; ++$index) { $a1 = ereg_replace("[^A-Za-z0-9]", "",$a[$index]); $b1 = ereg_replace("[^A-Za-z0-9]", "",$b[$index]); $equal = 0; if (is_numeric($a1) && is_numeric($b1)) { $equal = $a1 - $b1; } else { $equal = strcasecmp($a1,$b1); } if ($equal < 0) { return -1; } if ($equal > 0) { return 1; } } return count($a) - count($b); } ?>
Quicker (2012-01-05 13:53:43)
This one may approve multisort performance dramatically.
I had a 100K-row-array with assoc keys and sub arrays, several MBs. Using usort hammered my dev box cpu for several minutes until I killed it.
My own assoc-version of [someone else‘s code] did the same. Following Array-Indexing and sorting solution only took very few secs:
<?php
define(‘funcname‘,0);
define(‘indexfieldinfuncparamspos‘,1);
define(‘funcparams‘,2);
function array_index($dataarr,$field2funcarr){
$indexarr=array();
foreach($dataarr as $key=>$valarr) {
$currentindex=‘‘;
foreach($field2funcarr as $fieldid=>$funcarr) if(is_array($funcarr)) {
$funcarr[funcparams][$funcarr[indexfieldinfuncparamspos]]= $valarr[$fieldid];
$currentindex.= call_user_func_array($funcarr[funcname],$funcarr[funcparams]).‘_‘;
} else $currentindex.= $valarr[$fieldid].‘_‘;
$indexarr[$currentindex]=$key;
}
return $indexarr;
}
function array_sortbyindex(&$dataarr,$indexarr,$issortindexbykey=true){
// assumes complete index!: each item of indexarr must correlate a key of dataarr
$resultarr=array();
if($issortindexbykey) ksort($indexarr);
foreach($indexarr as $datakey) $resultarr[$datakey]= $dataarr[$datakey];
return $resultarr;
}
$dataarr=array(
‘Franz‘=>array(‘letters‘=>5,‘wordtype‘=>‘name‘),
‘goes‘=>array(‘letters‘=>4,‘wordtype‘=>‘verb‘),
‘to‘=>array(‘letters‘=>2,‘wordtype‘=>‘prep‘),
‘China‘=>array(‘letters‘=>5,‘wordtype‘=>‘noun‘));
// just build an index for interest (empty string for wordtype as no modification required):
print_r(array_index($dataarr, array(‘letters‘=>array(‘str_pad‘,0,array(‘‘,7,‘0‘,STR_PAD_LEFT)), ‘wordtype‘=>‘‘)));
// build index and sort - all in one go:
print_r(array_sortbyindex($dataarr, array_index($dataarr, array(‘letters‘=>array(‘str_pad‘,0, array(‘‘,7,‘0‘,STR_PAD_LEFT)), ‘wordtype‘=>‘‘))));
?>
first print_r returns:
Array
(
[0000005_name_] => Franz
[0000004_verb_] => goes
[0000002_prep_] => to
[0000005_noun_] => China
)
second print_r returns:
Array
(
[to] => Array
(
[letters] => 2
[wordtype] => prep
)
[goes] => Array
(
[letters] => 4
[wordtype] => verb
)
[Franz] => Array
(
[letters] => 5
[wordtype] => name
)
[China] => Array
(
[letters] => 5
[wordtype] => noun
)
)
Major Benefits:
- extremly fast
- each sort field can apply an own modifier. Ideally you can use out-of-the-box functions, which reduces effort for programming callbacks
- you could use the index eg. for sorted data output without physically sorting the data
admin at gosenz dot com (2011-12-04 20:58:38)
sort multi-dimentional arrays in class with usort
<?php class ArraySort { private $arr = array();
public function __construct($arr) { $this->arr = $arr; }
public function doSort() { $cmp = function($a, $b) { //Do Some Comparation } if(is_array($this->arr)) { usort($this->arr, $cmp); } return $this->arr; } } ?>
Gok6tm (2011-09-13 06:09:10)
this is a new multisort function for sorting on multiple subfield like it will be in sql : ‘ORDER BY field1, field2‘
number of sort field is undefined
<?php
$array[] = array(‘soc‘ => 3, ‘code‘=>1);
$array[] = array(‘soc‘ => 2, ‘code‘=>1);
$array[] = array(‘soc‘ => 1, ‘code‘=>1);
$array[] = array(‘soc‘ => 1, ‘code‘=>1);
$array[] = array(‘soc‘ => 2, ‘code‘=>5);
$array[] = array(‘soc‘ => 1, ‘code‘=>2);
$array[] = array(‘soc‘ => 3, ‘code‘=>2);
//usage
print_r(multiSort($array, ‘soc‘, ‘code‘));
function multiSort() {
//get args of the function
$args = func_get_args();
$c = count($args);
if ($c < 2) {
return false;
}
//get the array to sort
$array = array_splice($args, 0, 1);
$array = $array[0];
//sort with an anoymous function using args
usort($array, function($a, $b) use($args) {
$i = 0;
$c = count($args);
$cmp = 0;
while($cmp == 0 && $i < $c)
{
$cmp = strcmp($a[ $args[ $i ] ], $b[ $args[ $i ] ]);
$i++;
}
return $cmp;
});
return $array;
}
?>
output:
Array
(
[0] => Array
(
[soc] => 1
[code] => 1
)
[1] => Array
(
[soc] => 1
[code] => 1
)
[2] => Array
(
[soc] => 1
[code] => 2
)
[3] => Array
(
[soc] => 2
[code] => 1
)
[4] => Array
(
[soc] => 2
[code] => 5
)
[5] => Array
(
[soc] => 3
[code] => 1
)
[6] => Array
(
[soc] => 3
[code] => 2
)
)
neculitairinel at yahoo dot com (2011-08-19 06:12:51)
Here is another date sort, in case you have hours and minutes in the dates.
<?php
function DateSort($a,$b,$d="-") {
if ($a == $b) {
return 0;
} else {
$a = strtotime($a);
$b = strtotime($b);
if($a<$b) {
return -1;
} else {
return 1;
}
}
}
?>
Lea Hayes (2011-07-12 17:55:13)
<?php
/**
* Sort array of objects by field.
*
* @param array $objects Array of objects to sort.
* @param string $on Name of field.
* @param string $order (ASC|DESC)
*/
function sort_on_field(&$objects, $on, $order = ‘ASC‘) {
$comparer = ($order === ‘DESC‘)
? "return -strcmp(\$a->{$on},\$b->{$on});"
: "return strcmp(\$a->{$on},\$b->{$on});";
usort($objects, create_function(‘$a,$b‘, $comparer));
}
?>
bcsj (2011-06-28 11:12:43)
Sorting a multidimensional array by a subkey seem to be one of the bigger challenges when using usort. At least if one want the key to be dynamic. For anyone interested this code seemed to work rather well for me:
<?php
usort($array,array(new cmp($key), "cmp__"));
class cmp { var $key; function __construct($key) { $this->key = $key; } function cmp__($a,$b) { $key = $this->key; if ($a[$key] == $b[$key]) return 0; return (($a[$key] > $b[$key]) ? 1 : -1); } }
?>
masonswolf+ignorethispart at gmail dot com (2011-06-13 10:42:03)
[The second version of a function I wrote], just a little cleaner to use, since the usort call is now folded into the custom ‘usortByArrayKey‘ function.
Seems like this is a popular problem - sorting an array of arrays by the keys of sub-arrays, so I‘ll go ahead and throw in an approach I haven‘t seen anyone mention yet. It only works since PHP 5.3 because that‘s when anonymous functions got added to the language.
<?php
function usortByArrayKey(&$array, $key, $asc=SORT_ASC) {
$sort_flags = array(SORT_ASC, SORT_DESC);
if(!in_array($asc, $sort_flags)) throw new InvalidArgumentException(‘sort flag only accepts SORT_ASC or SORT_DESC‘);
$cmp = function(array $a, array $b) use ($key, $asc, $sort_flags) {
if(!is_array($key)) { //just one key and sort direction
if(!isset($a[$key]) || !isset($b[$key])) {
throw new Exception(‘attempting to sort on non-existent keys‘);
}
if($a[$key] == $b[$key]) return 0;
return ($asc==SORT_ASC xor $a[$key] < $b[$key]) ? 1 : -1;
} else { //using multiple keys for sort and sub-sort
foreach($key as $sub_key => $sub_asc) {
//array can come as ‘sort_key‘=>SORT_ASC|SORT_DESC or just ‘sort_key‘, so need to detect which
if(!in_array($sub_asc, $sort_flags)) { $sub_key = $sub_asc; $sub_asc = $asc; }
//just like above, except ‘continue‘ in place of return 0
if(!isset($a[$sub_key]) || !isset($b[$sub_key])) {
throw new Exception(‘attempting to sort on non-existent keys‘);
}
if($a[$sub_key] == $b[$sub_key]) continue;
return ($sub_asc==SORT_ASC xor $a[$sub_key] < $b[$sub_key]) ? 1 : -1;
}
return 0;
}
};
usort($array, $cmp);
};
?>
Examples:
1) Sort a multi-dimensional array by a single key, from least to greatest:
usortByArrayKey($resultset, ‘order_id‘);
2) Sort a multi-dimensional array by a single key, from greatest to least:
usortByArrayKey($resultset, ‘purchase_amount‘, SORT_DESC);
3) Sort a multi-dimensional array first by one key, but then by a different key when the first one is equal, both from least to greatest:
usortByArrayKey($resultset, array(‘product_id‘, ‘price‘));
4) Sort a multi-dimensional array by two different keys from least to greatest, and then a third from greatest to least if the first two keys map to the equal values:
usortByArrayKey($resultset, array(‘product_id‘, ‘customer_id‘, ‘date‘=>SORT_DESC));
5) Sort a multi-dimensional array by multiple keys, all from greatest to least:
usortByArrayKey($resultset, array(‘product_id‘, ‘price‘), SORT_DESC);
One word of caution, since SORT_ASC and SORT_DESC have actual int values of 4 and 3, respectively, if you need to sort a multi-dimensional array by keys 3 or 4, and you‘re using an array to pass in your keys, you MUST specify your sort flags (e.g. array(3 => SORT_ASC,...)) to prevent unexpected behavior, instead of relying on the function‘s second parameter as your default sort flag.
cuonghuyto at gmail dot com (2011-03-02 02:42:09)
Some contribution towards a specification of usort()
------
- If you don‘t provide the callback function, an error would be raised: "usort(): Invalid comparison function."
- If your callback function doesn‘t return anything, or returns any value other than -1 or +1 (e.g. 0, 2, -2), then usort() would treat your sorting purpose as if there is no comparison operator provided, and it would actually change your list into an undefined order
------
markfiend at gmail dot com (2011-02-21 02:22:41)
To sort a multidimensional array (such as is returned from database query) by the values in $array[foo][$key]
e.g. <?php /** Potential pitfall if there is already a key of ‘__________‘ * in the subarrays. Not likely I hope! * ------------------------------------------------------------- */ function array_sort_by_subval(&$array, $key) { foreach($array as &$v) { $v[‘__________‘] = $v[$key]; } usort($array, ‘sort_by_underscores‘); foreach($array as &$v) { unset($v[‘__________‘]); } }
function sort_by_underscores($a, $b) { if($a[‘__________‘] == $b[‘__________‘]) return 0; if($a[‘__________‘] < $b[‘__________‘]) return -1; return 1; }
$n = array(array(‘a‘ => 0, ‘b‘ => 7, ‘c‘ => 2), array(‘a‘ => 4, ‘b‘ => 1, ‘c‘ => 3), array(‘a‘ => 7, ‘b‘ => 3, ‘c‘ => 1));
array_sort_by_subval($n, ‘b‘); ?> The array $n will now be: array(array(‘a‘ => 4, ‘b‘ => 1, ‘c‘ => 3), array(‘a‘ => 7, ‘b‘ => 3, ‘c‘ => 1), array(‘a‘ => 0, ‘b‘ => 7, ‘c‘ => 2))
cmanley_nl (2011-01-24 11:55:40)
I had to sort a result set by host. I made this comparator function to use in usort calls.
Sorts by host segment so that a.example.org comes after b.example.com, etc.
<?php
function hostcmp($a, $b) {
$a = strtolower($a);
$b = strtolower($b);
if ($a == $b) {
return 0;
}
$parts_a = array_reverse(explode(‘.‘, $a));
$parts_b = array_reverse(explode(‘.‘, $b));
$max = max(count($parts_a), count($parts_b));
for ($i=0; $i < $max; $i++) {
if (($i < count($parts_a)) && ($i < count($parts_b))) {
if ($c = strcmp($parts_a[$i],$parts_b[$i])) {
return $c;
}
}
else {
// Return numeric cmp on array sizes. PHP doesn‘t have a <=> operator, so emulate it.
//return count($parts_a) <=> count($parts_b);
return count($parts_a) == count($parts_b) ? 0 : (count($parts_a) < count($parts_b) ? -1 : 1);
}
}
return 0;
}
?>
fmaz008 at gmail dot com (2010-09-29 14:23:36)
This comment is just to help backward compatibility.
I needed to have a foreach loop using reference just before using the usort function on the same array that was used in the foreach.
Like this: <?php public function sortByTitle() { if(empty($this->_arrSubCat)) return false; foreach($this->_arrSubCat as &$cat) $cat->sortByTitle(); usort($this->_arrSubCat, ‘strcasecmp‘); } ?> I had this strange bug where the last object of the $this->_arrSubCat array before the sort was alway replaced/overwrited with his string value.
On my machine (PHP 5.3), I had no problem, but when I placed the code on another server, my code crashed with a fatal error (Because I was using a string as an object later in the code)
The solution I found is really simple, and avoid the array to have a reference declared in memory while running the sort function. Just add an unset($cat):
<?php public function sortByTitle() { if(empty($this->_arrSubCat)) return false; foreach($this->_arrSubCat as &$cat) $cat->sortByTitle(); unset($cat); //No more problem because of the foreach &cat reference. usort($this->_arrSubCat, ‘strcasecmp‘); } ?> It took me an hour an a half to locate the bug, hope it will save someone some time !
phil at lavin dot me dot uk (2010-08-01 11:06:07)
strcmp (or strcasecmp) can be used as a callback function for usort. It will cast your comparison values to string. Thus, you can implement a __toString() method into your classes and use usort without creating a callback function:
<?php class Foo { private $a; private $b;
public function __construct($a, $b) { $this->a = $a; $this->b = $b; }
public function __toString() { return (string)$this->a; } }
$foo = array(new Foo(‘t‘, ‘b‘), new Foo(‘a‘, ‘c‘), new Foo(‘g‘, ‘d‘));
print_r($foo);
usort($foo, ‘strcasecmp‘);
print_r($foo); ?>
xaguilars at gmail dot com (2010-05-06 04:03:29)
I‘d like to share with the community my function for sorting an array of arrays or objects containing associative data. This could be used, for example, with a MySQL result.
<?php function sort_by($field, &$arr, $sorting=SORT_ASC, $case_insensitive=true){ if(is_array($arr) && (count($arr)>0) && ( ( is_array($arr[0]) && isset($arr[0][$field]) ) || ( is_object($arr[0]) && isset($arr[0]->$field) ) ) ){ if($case_insensitive==true) $strcmp_fn = "strnatcasecmp"; else $strcmp_fn = "strnatcmp";
if($sorting==SORT_ASC){ $fn = create_function(‘$a,$b‘, ‘ if(is_object($a) && is_object($b)){ return ‘.$strcmp_fn.‘($a->‘.$field.‘, $b->‘.$field.‘); }else if(is_array($a) && is_array($b)){ return ‘.$strcmp_fn.‘($a["‘.$field.‘"], $b["‘.$field.‘"]); }else return 0; ‘); }else{ $fn = create_function(‘$a,$b‘, ‘ if(is_object($a) && is_object($b)){ return ‘.$strcmp_fn.‘($b->‘.$field.‘, $a->‘.$field.‘); }else if(is_array($a) && is_array($b)){ return ‘.$strcmp_fn.‘($b["‘.$field.‘"], $a["‘.$field.‘"]); }else return 0; ‘); } usort($arr, $fn); return true; }else{ return false; } } ?>
Alex Rath (2010-04-17 11:35:51)
This is the perfect Place for anonymous Functions, here an Example:
<?php
$array = array(3, 2, 5, 6, 1);
usort($array, function($func_a, $func_b) { if($func_a == $func_b) return 0; return ($func_a < $func_b) ? -1 : 1; });
foreach ($array as $key => $value) echo "$key: $value\n";
?>
nicolas dot demarque at gmail dot com (2010-04-10 11:37:09)
Another way to compare object is to have a compare static function in the class with reccursion ability and have globals or static variables who save the state of comparison, and the order.
It could be a good idea to have a variable with comparison functions name (with the sorting : numeric, alphanumeric, inverse).
<?php interface Comparable{static function compare($a, $b);} class myObj implements Comparable{ var $var1; var $var2; var $var3; function __construct($v1, $v2, $v3){ $this->var1=$v1; $this->var2=$v2; $this->var3=$v3; } public function __toString() { return "v1 ".$this->var1." v2 ".$this->var2." v3 ".$this->var3; } static function compare($a, $b){ $sort=$GLOBALS[‘sorts‘][$GLOBALS[‘sort‘]]; echo "$sort\n"; if($a->$sort == $b->$sort){ if($GLOBALS[‘sorts‘][$GLOBALS[‘sort‘]+1]){ $GLOBALS[‘sort‘]++; $res= call_user_func(array(‘myObj‘, ‘compare‘), $a, $b); $GLOBALS[‘sort‘]=0; return $res; } $GLOBALS[‘sort‘]=0; return 0; } $GLOBALS[‘sort‘]=0; if($a->$sort > $b->$sort) return 1; return -1; } }
$objects = array(new myObj("1", "2", "3"), new myObj("2", "2", "2"), new myObj("1", "3", "4"));
/* Tests */ $sorts=Array(‘var1‘, ‘var2‘, ‘var3‘); $sort = 0; usort($objects, array(‘myObj‘, ‘compare‘)); echo ("var1 var2 var3\n"); foreach($objects as $o)echo $o."\n"; $sorts=Array(‘var2‘, ‘var3‘, ‘var1‘); $sort = 0; usort($objects, array(‘myObj‘, ‘compare‘)); echo ("\nvar2 var3 var1\n"); foreach($objects as $o)echo $o."\n"; $sorts=Array(