我遇到了PHP usort()
的问题。让我们假设我有一个这样的数组(这是一个简化,我不使用名称,我有一个对象数组,而不是数组):
$data = array(
array('name' => 'Albert', 'last' => 'Einstein'),
array('name' => 'Lieserl', 'last' => 'Einstein'),
array('name' => 'Alan', 'last' => 'Turing' ),
array('name' => 'Mileva', 'last' => 'Einstein'),
array('name' => 'Hans Albert', 'last' => 'Einstein')
);
如您所见,数组是任意排序的。
现在,如果想按last
对其进行排序,我会这样做:
function sort_some_people($a, $b) { return strcmp($a['last'], $b['last']); }
usort($data, 'sort_some_people');
我有:
Array (
[0] => Array ( [name] => Mileva [last] => Einstein )
[3] => Array ( [name] => Albert [last] => Einstein )
[1] => Array ( [name] => Lieserl [last] => Einstein )
[2] => Array ( [name] => Hans Albert [last] => Einstein )
[4] => Array ( [name] => Alan [last] => Turing )
)
没关系,现在它们按last
排序。但是,正如你所看到的,我刚刚完全失去了之前的排序。我在说什么呢?我希望像以前一样保留数组排序,但是作为辅助排序。我希望我很清楚。 实际我想使用usort()
(因此,完全自定义排序)对数据进行排序,但如果两个项目之间的排序字段相同,我希望保持其相对位置就像以前一样。考虑到给定的示例,我希望Lieserl Einstein
出现在Mileva Einstein
之前,因为它在开始时就是这样。
答案 0 :(得分:2)
PHP中使用的排序算法具有此属性,如果项匹配,则订单未定义。
如果您需要保留订单,则必须滚动自己的代码。
幸运的是,有人已经: http://www.php.net/manual/en/function.usort.php#38827
$data = array(
array('name' => 'Albert', 'last' => 'Einstein'),
array('name' => 'Lieserl', 'last' => 'Einstein'),
array('name' => 'Alan', 'last' => 'Turing' ),
array('name' => 'Mileva', 'last' => 'Einstein'),
array('name' => 'Hans Albert', 'last' => 'Einstein')
);
function sort_some_people($a, $b) {
return strcmp($a['last'], $b['last']);
}
function mergesort(&$array, $cmp_function = 'strcmp') {
// Arrays of size < 2 require no action.
if (count($array) < 2) return;
// Split the array in half
$halfway = count($array) / 2;
$array1 = array_slice($array, 0, $halfway);
$array2 = array_slice($array, $halfway);
// Recurse to sort the two halves
mergesort($array1, $cmp_function);
mergesort($array2, $cmp_function);
// If all of $array1 is <= all of $array2, just append them.
if (call_user_func($cmp_function, end($array1), $array2[0]) < 1) {
$array = array_merge($array1, $array2);
return;
}
// Merge the two sorted arrays into a single sorted array
$array = array();
$ptr1 = $ptr2 = 0;
while ($ptr1 < count($array1) && $ptr2 < count($array2)) {
if (call_user_func($cmp_function, $array1[$ptr1], $array2[$ptr2]) < 1) {
$array[] = $array1[$ptr1++];
}
else {
$array[] = $array2[$ptr2++];
}
}
// Merge the remainder
while ($ptr1 < count($array1)) $array[] = $array1[$ptr1++];
while ($ptr2 < count($array2)) $array[] = $array2[$ptr2++];
return;
}
mergesort($data, 'sort_some_people');
print_r($data);
输出:
Array
(
[0] => Array
(
[name] => Albert
[last] => Einstein
)
[1] => Array
(
[name] => Lieserl
[last] => Einstein
)
[2] => Array
(
[name] => Mileva
[last] => Einstein
)
[3] => Array
(
[name] => Hans Albert
[last] => Einstein
)
[4] => Array
(
[name] => Alan
[last] => Turing
)
)
瞧!
答案 1 :(得分:1)
$compare = strcmp($a['last'], $b['last']);
if ($compare == 0)
$compare = strcmp($a['name'], $b['name']);
return $compare
答案 2 :(得分:1)
你要的是stable sorting algorithm,php没有提供。请注意,即使它有时看起来稳定,也不能保证它,并且在给定某些输入的情况下可能会出现行为异常。
如果您知道其他列的排序条件,则可以立即使用它们来获得所需的行为。 array_multisort这样做。以下是一种更强大的方法,因为比较逻辑完全是用户定义的。
// should behave similar to sql "order by last, first"
$comparatorSequence = array(
function($a, $b) {
return strcmp($a['last'], $b['last']);
}
, function($a, $b) {
return strcmp($a['first'], $b['first']);
}
// more functions as needed
);
usort($theArray, function($a, $b) use ($comparatorSequence) {
foreach ($comparatorSequence as $cmpFn) {
$diff = call_user_func($cmpFn, $a, $b);
if ($diff !== 0) {
return $diff;
}
}
return 0;
});
如果你真的需要一个稳定的排序,因为现有的元素顺序没有明确定义,请尝试编写自己的排序。例如,bubble sort非常容易编写。只要列表中的元素数量相对较少,这是一个很好的解决方案,否则就要实现其他稳定的排序算法之一。
答案 3 :(得分:0)
试试这个:
function sort_some_people($a, $b)
{
$compareValue = 10 * strcmp($a['last'], $b['last']);
$compareValue += 1 * strcmp($a['name'], $b['name']);
return $compareValue;
}
示例:http://codepad.org/zkHviVBM
此函数使用十进制系统的每个数字作为排序条件。首先出现的数字最高。可能不是最聪明,但对我有用。