How do I Sort a Multidimensional Array in PHP
我将csv数据加载到多维数组中。这样,每个"行"都是一条记录,每个"列"都包含相同类型的数据。我正在使用下面的函数加载我的csv文件。
1 2 3 4 5 6 7 8 9 10 11 | function f_parse_csv($file, $longest, $delimiter) { $mdarray = array(); $file = fopen($file,"r"); while ($line = fgetcsv($file, $longest, $delimiter)) { array_push($mdarray, $line); } fclose($file); return $mdarray; } |
我需要能够指定一列进行排序,以便重新排列行。其中一列包含
介绍:针对php 5.3的一个非常通用的解决方案+
我想在这里添加我自己的解决方案,因为它提供了其他答案不能提供的功能。好的。
具体来说,此解决方案的优势包括:好的。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | function make_comparer() { // Normalize criteria up front so that the comparer finds everything tidy $criteria = func_get_args(); foreach ($criteria as $index => $criterion) { $criteria[$index] = is_array($criterion) ? array_pad($criterion, 3, null) : array($criterion, SORT_ASC, null); } return function($first, $second) use (&$criteria) { foreach ($criteria as $criterion) { // How will we compare this round? list($column, $sortOrder, $projection) = $criterion; $sortOrder = $sortOrder === SORT_DESC ? -1 : 1; // If a projection was defined project the values now if ($projection) { $lhs = call_user_func($projection, $first[$column]); $rhs = call_user_func($projection, $second[$column]); } else { $lhs = $first[$column]; $rhs = $second[$column]; } // Do the actual comparison; do not return if equal if ($lhs < $rhs) { return -1 * $sortOrder; } else if ($lhs > $rhs) { return 1 * $sortOrder; } } return 0; // tiebreakers exhausted, so $first == $second }; } |
如何使用
在本节中,我将提供对示例数据集进行排序的链接:好的。
1 2 3 4 5 6 | $data = array( array('zz', 'name' => 'Jack', 'number' => 22, 'birthday' => '12/03/1980'), array('xx', 'name' => 'Adam', 'number' => 16, 'birthday' => '01/12/1979'), array('aa', 'name' => 'Paul', 'number' => 16, 'birthday' => '03/11/1987'), array('cc', 'name' => 'Helen', 'number' => 44, 'birthday' => '24/06/1967'), ); |
基础知识
函数
最简单的用例是传入要用于比较数据项的键。例如,要按
行动起来看看。好的。
如果项是数字索引数组,则键也可以是数字。对于问题中的示例,这将是好的。
1 |
行动起来看看。好的。多个排序列
通过向
1 |
行动起来看看。好的。高级功能
如果将排序列指定为数组而不是简单字符串,则可以使用更高级的功能。这个数组应该是数字索引的,并且必须包含这些项:好的。
1 2 3 | 0 => the column name to sort on (mandatory) 1 => either SORT_ASC or SORT_DESC (optional) 2 => a projection function (optional) |
让我们看看如何使用这些功能。好的。反向排序
按名称降序排序:好的。
1 |
行动起来看看。好的。
要按数字降序排序,然后按名称降序排序:好的。
1 |
行动起来看看。好的。自定义投影
在某些情况下,可能需要按值不适合排序的列进行排序。示例数据集中的"生日"列符合此描述:将生日作为字符串进行比较是没有意义的(例如,"01/01/1980"在"10/10/1970"之前)。在这种情况下,我们希望指定如何将实际数据投影到可以直接与所需语义进行比较的表单。好的。
投影可以指定为任何类型的可调用:字符串、数组或匿名函数。假设一个投影接受一个参数并返回其投影形式。好的。
需要注意的是,虽然投影类似于与
让我们对没有投影的示例数据集进行排序,看看会发生什么:好的。
1 |
行动起来看看。好的。
这不是预期的结果。但我们可以使用
1 |
行动起来看看。好的。
这是我们想要的正确顺序。好的。
还有很多事情是可以实现的。例如,快速获得不区分大小写排序的方法是使用
这就是说,我还应该提到,如果数据集很大,最好不要使用投影:在这种情况下,提前手动投影所有数据,然后在不使用投影的情况下进行排序要快得多,尽管这样做会牺牲内存使用量的增加来获得更快的排序速度。好的。
最后,下面是一个使用所有特性的示例:它首先按数字降序排序,然后按生日升序排序:好的。2
行动起来看看。好的。好啊。
您可以使用array_multisort()。
尝试如下操作:
2对于php>=5.5.0,只需提取要排序的列。不需要循环:
1 |
随附。下面是一个通用的解决方案,可以用于不同的列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class TableSorter { protected $column; function __construct($column) { $this->column = $column; } function sort($table) { usort($table, array($this, 'compare')); return $table; } function compare($a, $b) { if ($a[$this->column] == $b[$this->column]) { return 0; } return ($a[$this->column] < $b[$this->column]) ? -1 : 1; } } |
按第一列排序:
1 2 |
使用闭包进行多行排序
下面是另一种使用uasort()和匿名回调函数(closure)的方法。我经常使用这个功能。需要php 5.3–不再依赖!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /** * Sorting array of associative arrays - multiple row sorting using a closure. * See also: http://the-art-of-web.com/php/sortarray/ * * @param array $data input-array * @param string|array $fields array-keys * @license Public Domain * @return array */ function sortArray( $data, $field ) { $field = (array) $field; uasort( $data, function($a, $b) use($field) { $retval = 0; foreach( $field as $fieldname ) { if( $retval == 0 ) $retval = strnatcmp( $a[$fieldname], $b[$fieldname] ); } return $retval; } ); return $data; } /* example */ $data = array( array("firstname" =>"Mary","lastname" =>"Johnson","age" => 25 ), array("firstname" =>"Amanda","lastname" =>"Miller","age" => 18 ), array("firstname" =>"James","lastname" =>"Brown","age" => 31 ), array("firstname" =>"Patricia","lastname" =>"Williams","age" => 7 ), array("firstname" =>"Michael","lastname" =>"Davis","age" => 43 ), array("firstname" =>"Sarah","lastname" =>"Miller","age" => 24 ), array("firstname" =>"Patrick","lastname" =>"Miller","age" => 27 ) ); $data = sortArray( $data, 'age' ); $data = sortArray( $data, array( 'lastname', 'firstname' ) ); |
1 2 3 4 5 6 7 | function cmp($a, $b) { $p1 = $a['price']; $p2 = $b['price']; return (float)$p1 > (float)$p2; } uasort($my_array,"cmp"); |
http://qaify.com/sort-an-array-of-associative-array-by-value-of-given-key-in-php/
我知道这个问题已经问了2年了,但这里还有一个对二维数组排序的函数。它接受可变数量的参数,允许您传入多个要排序的键(即列名)。需要php 5.3。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function sort_multi_array ($array, $key) { $keys = array(); for ($i=1;$i<func_num_args();$i++) { $keys[$i-1] = func_get_arg($i); } // create a custom search function to pass to usort $func = function ($a, $b) use ($keys) { for ($i=0;$i<count($keys);$i++) { if ($a[$keys[$i]] != $b[$keys[$i]]) { return ($a[$keys[$i]] < $b[$keys[$i]]) ? -1 : 1; } } return 0; }; usort($array, $func); return $array; } |
在这里试试:http://www.exorithm.com/algorithm/view/sort_multi_array
"usort"函数就是您的答案。http://php.net/us端口
下面是将对一个或多个字段进行排序的php4/php5类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | // a sorter class // php4 and php5 compatible class Sorter { var $sort_fields; var $backwards = false; var $numeric = false; function sort() { $args = func_get_args(); $array = $args[0]; if (!$array) return array(); $this->sort_fields = array_slice($args, 1); if (!$this->sort_fields) return $array(); if ($this->numeric) { usort($array, array($this, 'numericCompare')); } else { usort($array, array($this, 'stringCompare')); } return $array; } function numericCompare($a, $b) { foreach($this->sort_fields as $sort_field) { if ($a[$sort_field] == $b[$sort_field]) { continue; } return ($a[$sort_field] < $b[$sort_field]) ? ($this->backwards ? 1 : -1) : ($this->backwards ? -1 : 1); } return 0; } function stringCompare($a, $b) { foreach($this->sort_fields as $sort_field) { $cmp_result = strcasecmp($a[$sort_field], $b[$sort_field]); if ($cmp_result == 0) continue; return ($this->backwards ? -$cmp_result : $cmp_result); } return 0; } } ///////////////////// // usage examples // some starting data $start_data = array( array('first_name' => 'John', 'last_name' => 'Smith', 'age' => 10), array('first_name' => 'Joe', 'last_name' => 'Smith', 'age' => 11), array('first_name' => 'Jake', 'last_name' => 'Xample', 'age' => 9), ); // sort by last_name, then first_name $sorter = new Sorter(); print_r($sorter->sort($start_data, 'last_name', 'first_name')); // sort by first_name, then last_name $sorter = new Sorter(); print_r($sorter->sort($start_data, 'first_name', 'last_name')); // sort by last_name, then first_name (backwards) $sorter = new Sorter(); $sorter->backwards = true; print_r($sorter->sort($start_data, 'last_name', 'first_name')); // sort numerically by age $sorter = new Sorter(); $sorter->numeric = true; print_r($sorter->sort($start_data, 'age')); |
我尝试了几个流行的数组multisort()和usort()答案,但没有一个对我有用。数据变得混乱,代码无法读取。这是一个快速而肮脏的解决方案。警告:只有当你确信一个流氓定界符以后不会回来骚扰你时,才使用这个!
假设多数组中的每一行看起来像:name、stuff1、stuff2:
1 2 3 4 5 6 | // Sort by name, pull the other stuff along for the ride foreach ($names_stuff as $name_stuff) { // To sort by stuff1, that would be first in the contatenation $sorted_names[] = $name_stuff[0] .','. name_stuff[1] .','. $name_stuff[2]; } sort($sorted_names, SORT_STRING); |
需要按字母顺序把东西放回去吗?
1 2 3 4 5 6 | foreach ($sorted_names as $sorted_name) { $name_stuff = explode(',',$sorted_name); // use your $name_stuff[0] // use your $name_stuff[1] // ... } |
是的,很脏。但超级简单,不会让你的头爆炸。
在我能够运行TableSorter类之前,我已经根据Shinhan提供的功能想出了一个函数。
1 2 3 4 5 6 7 8 9 10 | function sort2d_bycolumn($array, $column, $method, $has_header) { if ($has_header) $header = array_shift($array); foreach ($array as $key => $row) { $narray[$key] = $row[$column]; } array_multisort($narray, $method, $array); if ($has_header) array_unshift($array, $header); return $array; } |
- $array是要排序的MD数组。
- $column是要排序的列。
- $method是执行排序的方式,例如排序描述
- 如果第一行包含不希望排序的标题值,$has_header设置为true。
我更喜欢使用阵列多端口。参见文档在这里。