dec*_*eze 283 php arrays sorting spl object
此问题旨在作为有关在PHP中排序数组的问题的参考.很容易认为您的特定情况是独一无二的,值得一个新问题,但大多数实际上是本页面上其中一个解决方案的微小变化.
如果您的问题与此问题的副本相同,请仅在您能够解释为何与以下所有问题明显不同时才要求重新打开您的问题.
如何在PHP中对数组进行排序?
如何在PHP中对复杂数组进行排序?
如何在PHP中对对象数组进行排序?
有关使用PHP现有函数的实际答案,请参阅1.,有关排序算法的学术详细答案(PHP的函数实现以及您可能需要哪些非常复杂的案例),请参阅参考资料2.
dec*_*eze 157
$array = array(3, 5, 2, 8);
Run Code Online (Sandbox Code Playgroud)
适用的排序功能:
sort
rsort
asort
arsort
natsort
natcasesort
ksort
krsort
它们之间的区别仅在于是否保留了键值关联(" a
"函数),是对它进行排序从低到高还是反向(" r
"),是对值还是键(" k
")进行排序以及它如何比较值(" nat
"与正常人相比).见http://php.net/manual/en/array.sorting.php详细信息,并链接到更多详细信息.
$array = array(
array('foo' => 'bar', 'baz' => 42),
array('foo' => ..., 'baz' => ...),
...
);
Run Code Online (Sandbox Code Playgroud)
如果要按$array
每个条目的键'foo' 排序,则需要自定义比较功能.上述sort
和相关函数适用于他们知道如何比较和排序的简单值.PHP不只是"知道"做什么用复值样array('foo' => 'bar', 'baz' => 42)
虽然; 所以你需要告诉它.
为此,您需要创建一个比较函数.该函数需要两个元素,0
如果这些元素被认为是相等的,则必须返回,低于0
第一个值低的值,值高于0
第一个值高的值.这就是所需要的:
function cmp(array $a, array $b) {
if ($a['foo'] < $b['foo']) {
return -1;
} else if ($a['foo'] > $b['foo']) {
return 1;
} else {
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
通常,您会希望使用匿名函数作为回调.如果要使用方法或静态方法,请参阅在PHP中指定回调的其他方法.
然后,您可以使用以下功能之一:
同样,它们只是在保持键值关联和按值或键排序方面有所不同.阅读他们的文档了解详情.
用法示例:
usort($array, 'cmp');
Run Code Online (Sandbox Code Playgroud)
usort
将从数组中获取两个项目并cmp
使用它们调用您的函数.所以cmp()
将与$a
as array('foo' => 'bar', 'baz' => 42)
和$b
另一个一起调用array('foo' => ..., 'baz' => ...)
.然后函数返回usort
哪个值更大或它们是否相等.usort
重复此过程传递不同的值$a
,$b
直到对数组进行排序.该cmp
函数将被调用多次,至少与其中的值一样多次$array
,$a
并且$b
每次都使用不同的值组合.
要习惯这个想法,试试这个:
function cmp($a, $b) {
echo 'cmp called with $a:', PHP_EOL;
var_dump($a);
echo 'and $b:', PHP_EOL;
var_dump($b);
}
Run Code Online (Sandbox Code Playgroud)
你所做的只是定义一种比较两个项目的自定义方式,这就是你所需要的.这适用于各种各样的价值观.
顺便说一句,这适用于任何值,值不必是复杂的数组.如果您想要进行自定义比较,也可以在简单的数字数组上进行.
sort
通过引用排序,并没有返回任何有用的东西!请注意,数组已就地排序,您无需将返回值分配给任何内容.$array = sort($array)
将替换数组true
,而不是排序数组.只是sort($array);
工作.
如果您想baz
按键(数字)排序,您只需要:
function cmp(array $a, array $b) {
return $a['baz'] - $b['baz'];
}
Run Code Online (Sandbox Code Playgroud)
由于PoWEr oF MATH,它返回值<0,0或> 0,具体取决于是否$a
低于,等于或大于$b
.
请注意,这对于float
值不适用,因为它们会减少到int
精度并失去精度.使用显式-1
,0
并1
而是返回值.
如果您有一个对象数组,它的工作方式相同:
function cmp($a, $b) {
return $a->baz - $b->baz;
}
Run Code Online (Sandbox Code Playgroud)
您可以在比较功能中执行任何操作,包括调用函数:
function cmp(array $a, array $b) {
return someFunction($a['baz']) - someFunction($b['baz']);
}
Run Code Online (Sandbox Code Playgroud)
第一个字符串比较版本的快捷方式:
function cmp(array $a, array $b) {
return strcmp($a['foo'], $b['foo']);
}
Run Code Online (Sandbox Code Playgroud)
strcmp
完全符合预期cmp
,返回-1
,0
或1
.
PHP 7引入了宇宙飞船运营商,它统一并简化了相似/更小/更大的比例:
function cmp(array $a, array $b) {
return $a['foo'] <=> $b['foo'];
}
Run Code Online (Sandbox Code Playgroud)
如果要主要按顺序排序foo
,但如果foo
两个元素相等,则排序依据baz
:
function cmp(array $a, array $b) {
if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
return $cmp;
} else {
return $a['baz'] - $b['baz'];
}
}
Run Code Online (Sandbox Code Playgroud)
对于那些熟悉的人来说,这相当于一个SQL查询ORDER BY foo, baz
.
另请参阅这个非常简洁的速记版本以及如何为任意数量的键动态创建这样的比较函数.
如果要将元素排序为"手动顺序",如"foo","bar","baz":
function cmp(array $a, array $b) {
static $order = array('foo', 'bar', 'baz');
return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}
Run Code Online (Sandbox Code Playgroud)
对于上述所有情况,如果您使用的是PHP 5.3或更高版本(并且您确实应该使用),请使用匿名函数来缩短代码并避免使用另一个全局函数:
usort($array, function (array $a, array $b) { return $a['baz'] - $b['baz']; });
Run Code Online (Sandbox Code Playgroud)
这就是复杂的多维数组排序的简单方法.再一次,只要考虑教PHP如何分辨两个项目中的哪个是"更大" ; 让PHP做实际的排序.
同样对于上述所有情况,要在升序和降序之间切换,只需交换$a
和$b
参数.例如:
return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending
Run Code Online (Sandbox Code Playgroud)
然后有一个特殊的array_multisort
,它允许你基于另一个排序一个数组:
$array1 = array( 4, 6, 1);
$array2 = array('a', 'b', 'c');
Run Code Online (Sandbox Code Playgroud)
这里的预期结果是:
$array2 = array('c', 'a', 'b'); // the sorted order of $array1
Run Code Online (Sandbox Code Playgroud)
使用array_multisort
到那里:
array_multisort($array1, $array2);
Run Code Online (Sandbox Code Playgroud)
从PHP 5.5.0开始,您可以使用array_column
从多维数组中提取列并对该列上的数组进行排序:
array_multisort(array_column($array, 'foo'), SORT_DESC, $array);
Run Code Online (Sandbox Code Playgroud)
从PHP 7.0.0开始,您还可以从对象数组中提取属性.
如果您有更常见的案例,请随时编辑此答案.
Bab*_*aba 138
大多数基本方法已经被deceze所覆盖,我会尝试查看其他类型的排序
SplHeap
class SimpleHeapSort extends SplHeap {
public function compare($a, $b) {
return strcmp($a, $b);
}
}
// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");
echo implode(PHP_EOL, iterator_to_array($heap));
Run Code Online (Sandbox Code Playgroud)
产量
c
b
a
Run Code Online (Sandbox Code Playgroud)
SplMaxHeap
SplMaxHeap类提供堆的主要功能,保持最大值.
$heap = new SplMaxHeap();
$heap->insert(1);
$heap->insert(2);
$heap->insert(3);
Run Code Online (Sandbox Code Playgroud)
SplMinHeap
SplMinHeap类提供堆的主要功能,保持最小值.
$heap = new SplMinHeap ();
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);
Run Code Online (Sandbox Code Playgroud)
冒泡排序,有时被错误地称为下沉排序,是一种简单的排序算法,通过重复单步执行排序列表,比较每对相邻项目并交换它们(如果它们的顺序错误).重复传递列表,直到不需要交换,这表明列表已排序.该算法的名称来自较小元素"冒泡"到列表顶部的方式.因为它只使用比较来操作元素,所以它是一种比较排序.尽管算法很简单,但大多数其他排序算法对于大型列表更有效.
function bubbleSort(array $array) {
$array_size = count($array);
for($i = 0; $i < $array_size; $i ++) {
for($j = 0; $j < $array_size; $j ++) {
if ($array[$i] < $array[$j]) {
$tem = $array[$i];
$array[$i] = $array[$j];
$array[$j] = $tem;
}
}
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
In computer science, selection sort is a sorting algorithm, specifically an in-place comparison sort. It has O(n2) time complexity, making it inefficient on large lists, and generally performs worse than the similar insertion sort. Selection sort is noted for its simplicity, and it has performance advantages over more complicated algorithms in certain situations, particularly where auxiliary memory is limited.
function selectionSort(array $array) {
$length = count($array);
for($i = 0; $i < $length; $i ++) {
$min = $i;
for($j = $i + 1; $j < $length; $j ++) {
if ($array[$j] < $array[$min]) {
$min = $j;
}
}
$tmp = $array[$min];
$array[$min] = $array[$i];
$array[$i] = $tmp;
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Insertion sort:
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. However, insertion sort provides several advantages:
function insertionSort(array $array) {
$count = count($array);
for($i = 1; $i < $count; $i ++) {
$j = $i - 1;
// second element of the array
$element = $array[$i];
while ( $j >= 0 && $array[$j] > $element ) {
$array[$j + 1] = $array[$j];
$array[$j] = $element;
$j = $j - 1;
}
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Shellsort:
Shellsort, also known as Shell sort or Shell's method, is an in-place comparison sort. It generalizes an exchanging sort, such as insertion or bubble sort, by starting the comparison and exchange of elements with elements that are far apart before finishing with neighboring elements.
function shellSort(array $array) {
$gaps = array(
1,
2,
3,
4,
6
);
$gap = array_pop($gaps);
$length = count($array);
while ( $gap > 0 ) {
for($i = $gap; $i < $length; $i ++) {
$tmp = $array[$i];
$j = $i;
while ( $j >= $gap && $array[$j - $gap] > $tmp ) {
$array[$j] = $array[$j - $gap];
$j -= $gap;
}
$array[$j] = $tmp;
}
$gap = array_pop($gaps);
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Comb sort:
Comb sort is a relatively simple sorting algorithm originally designed by Wlodzimierz Dobosiewicz in 1980. Later it was rediscovered by Stephen Lacey and Richard Box in 1991. Comb sort improves on bubble sort.
function combSort(array $array) {
$gap = count($array);
$swap = true;
while ( $gap > 1 || $swap ) {
if ($gap > 1)
$gap /= 1.25;
$swap = false;
$i = 0;
while ( $i + $gap < count($array) ) {
if ($array[$i] > $array[$i + $gap]) {
// swapping the elements.
list($array[$i], $array[$i + $gap]) = array(
$array[$i + $gap],
$array[$i]
);
$swap = true;
}
$i ++;
}
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Merge sort:
In computer science, a merge sort (also commonly spelled mergesort) is an O(n log n) comparison-based sorting algorithm. Most implementations produce a stable sort, which means that the implementation preserves the input order of equal elements in the sorted output
function mergeSort(array $array) {
if (count($array) <= 1)
return $array;
$left = mergeSort(array_splice($array, floor(count($array) / 2)));
$right = mergeSort($array);
$result = array();
while ( count($left) > 0 && count($right) > 0 ) {
if ($left[0] <= $right[0]) {
array_push($result, array_shift($left));
} else {
array_push($result, array_shift($right));
}
}
while ( count($left) > 0 )
array_push($result, array_shift($left));
while ( count($right) > 0 )
array_push($result, array_shift($right));
return $result;
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Quicksort:
Quicksort, or partition-exchange sort, is a sorting algorithm developed by Tony Hoare that, on average, makes O(n log n) comparisons to sort n items. In the worst case, it makes O(n2) comparisons, though this behavior is rare.
function quickSort(array $array) {
if (count($array) == 0) {
return $array;
}
$pivot = $array[0];
$left = $right = array();
for($i = 1; $i < count($array); $i ++) {
if ($array[$i] < $pivot) {
$left[] = $array[$i];
} else {
$right[] = $array[$i];
}
}
return array_merge(quickSort($left), array(
$pivot
), quickSort($right));
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Permutation sort:
Permutation sort, which proceeds by generating the possible permutations of the input array/list until discovering the sorted one.
function permutationSort($items, $perms = array()) {
if (empty($items)) {
if (inOrder($perms)) {
return $perms;
}
} else {
for($i = count($items) - 1; $i >= 0; -- $i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
$res = permutationSort($newitems, $newperms);
if ($res) {
return $res;
}
}
}
}
function inOrder($array) {
for($i = 0; $i < count($array); $i ++) {
if (isset($array[$i + 1])) {
if ($array[$i] > $array[$i + 1]) {
return False;
}
}
}
return True;
}
Run Code Online (Sandbox Code Playgroud)
From the Wikipedia article on Radix sort:
在计算机科学中,基数排序是一种非比较整数排序算法,它通过将密钥分组为具有相同重要位置和值的各个数字来对整数密钥进行排序.
// Radix Sort for 0 to 256
function radixSort($array) {
$n = count($array);
$partition = array();
for($slot = 0; $slot < 256; ++ $slot) {
$partition[] = array();
}
for($i = 0; $i < $n; ++ $i) {
$partition[$array[$i]->age & 0xFF][] = &$array[$i];
}
$i = 0;
for($slot = 0; $slot < 256; ++ $slot) {
for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) {
$array[$i ++] = &$partition[$slot][$j];
}
}
return $array;
}
Run Code Online (Sandbox Code Playgroud)
Ja͢*_*͢ck 43
假设你有一个像这样的数组:
['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']
Run Code Online (Sandbox Code Playgroud)
而现在你只想对第一个字母进行排序:
usort($array, function($a, $b) {
return strcmp($a[0], $b[0]);
});
Run Code Online (Sandbox Code Playgroud)
结果如下:
['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']
Run Code Online (Sandbox Code Playgroud)
那种不稳定!
敏锐的观察者可能已经注意到,数组排序算法(QuickSort)没有产生稳定的结果,并且没有保留相同第一个字母的单词之间的原始顺序.这个案例很简单,我们应该比较整个字符串,但是我们假设你的用例更复杂,比如不同字段上的两个连续排序不应该抵消彼此的工作.
施瓦茨变换
Schwartzian变换,也称为decorate-sort-undecorate习语,使用固有的不稳定排序算法实现稳定排序.
首先,使用包含主键(值)和辅助键(其索引或位置)的另一个数组来装饰每个数组元素:
array_walk($array, function(&$element, $index) {
$element = array($element, $index); // decorate
});
Run Code Online (Sandbox Code Playgroud)
这会将数组转换为:
[
['Kale', 0], ['Kaleidoscope', 1],
['Aardvark', 2], ['Apple', 3],
['Leicester', 4], ['Lovely', 5]
]
Run Code Online (Sandbox Code Playgroud)
现在,我们调整比较步骤; 我们再次比较第一个字母,但如果它们相同,则使用二级密钥保留原始排序:
usort($array, function($a, $b) {
// $a[0] and $b[0] contain the primary sort key
// $a[1] and $b[1] contain the secondary sort key
$tmp = strcmp($a[0][0], $b[0][0]);
if ($tmp != 0) {
return $tmp; // use primary key comparison results
}
return $a[1] - $b[1]; // use secondary key
});
Run Code Online (Sandbox Code Playgroud)
之后,我们不合理:
array_walk($array, function(&$element) {
$element = $element[0];
});
Run Code Online (Sandbox Code Playgroud)
最终结果:
['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']
Run Code Online (Sandbox Code Playgroud)
重用怎么样?
您必须重写比较函数才能使用转换后的数组元素; 您可能不想编辑精细的比较函数,因此这里是比较函数的包装器:
function stablecmp($fn)
{
return function($a, $b) use ($fn) {
if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
return $tmp;
} else {
return $a[1] - $b[1];
}
};
}
Run Code Online (Sandbox Code Playgroud)
让我们使用这个函数编写排序步骤:
usort($array, stablecmp(function($a, $b) {
return strcmp($a[0], $b[0]);
}));
Run Code Online (Sandbox Code Playgroud)
瞧!您的原始比较代码又回来了.
Ora*_*ill 15
从带有闭包的PHP 5.3开始,也可以使用闭包来确定排序的顺序.
例如,假设$ array是包含month属性的对象数组.
$orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");
usort($array, function($a, $b) use ($orderArray){
return array_search($a->month, $orderArray) - array_search($b->month, $orderArray);
});
Run Code Online (Sandbox Code Playgroud)
在.NET中,LINQ经常用于排序,它提供了比比较函数更好的语法,特别是当对象需要按多个字段排序时.LINQ到PHP有几个端口,包括YaLinqo库*.有了它,可以使用单行对数组进行排序,而无需编写复杂的比较函数.
$sortedByName = from($objects)->orderBy('$v->name');
$sortedByCount = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');
Run Code Online (Sandbox Code Playgroud)
通过将回调作为第二个参数传递,可以进一步定制比较,例如:
$sortedByFilenameNat = from($objects)->orderBy('$v->filename', 'strnatcmp');
Run Code Online (Sandbox Code Playgroud)
这里'$v->count'
是function ($v) { return $v->count; }
(可以使用)的简写.这些方法链返回迭代器,->toArray()
如果需要,可以通过最后添加迭代器将其转换为数组.
在内部,orderBy
以及相关的方法调用相应的数组排序功能(uasort
,krsort
,multisort
,usort
等等).
LINQ包含更多受SQL启发的方法:过滤,分组,连接,聚合等.它最适合需要在不依赖数据库的情况下执行阵列和对象的复杂转换的情况.
*由我开发,有关更多详细信息和与其他LINQ端口的比较,请参阅自述文件
归档时间: |
|
查看次数: |
60618 次 |
最近记录: |