深入PHP内核之array_multisort
这个函数是我第一次看手册的时候,没看明白是怎么回事,所以有必要记录一下
用法
bool array_multisort ( array &$arr
[, mixed $arg
= SORT_ASC [, mixed $arg
= SORT_REGULAR [, mixed $...
]]] )
array_multisort() 可以用来一次对多个数组进行排序,或者根据某一维或多维对多维数组进行排序。
关联(string)键名保持不变,但数字键名会被重新索引。
排序顺序标志:
SORT_ASC
- 按照上升顺序排序SORT_DESC
- 按照下降顺序排序
排序类型标志:
SORT_REGULAR
- 将项目按照通常方法比较SORT_NUMERIC
- 将项目按照数值比较SORT_STRING
- 将项目按照字符串比较
每个数组之后不能指定两个同类的排序标志。每个数组后指定的排序标志仅对该数组有效 - 在此之前为默认值 SORT_ASC
和 SORT_REGULAR
。
输入数组被当成一个表的列并以行来排序——这类似于 SQL 的 ORDER BY 子句的功能。第一个数组是要排序的主要数组。数组中的行(值)比较为相同的话就按照下一个输入数组中相应值的大小来排序,依此类推。
本函数的参数结构有些不同寻常,但是非常灵活。第一个参数必须是一个数组。接下来的每个参数可以是数组或者是下面列出的排序标志。
示例一:
<?php
function my_sort($arrays, $sort_key, $sort_order = SORT_ASC, $sort_type = SORT_NUMERIC)
{
if (is_array($arrays)) {
foreach ($arrays as $array) {
if (is_array($array)) {
$key_arrays[] = $array[$sort_key];
} else {
return false;
}
}
} else {
return false;
}
array_multisort($key_arrays, $sort_order, $sort_type, $arrays);
return $arrays;
} $person = array(
array('id' => 1, 'name' => 'fj', 'weight' => 100, 'height' => 180),
array('id' => 2, 'name' => 'tom', 'weight' => 53, 'height' => 150),
array('id' => 3, 'name' => 'jerry', 'weight' => 120, 'height' => 156),
array('id' => 4, 'name' => 'bill', 'weight' => 110, 'height' => 190),
array('id' => 5, 'name' => 'linken', 'weight' => 80, 'height' => 200),
array('id' => 6, 'name' => 'madana', 'weight' => 95, 'height' => 110),
array('id' => 7, 'name' => 'jordan', 'weight' => 70, 'height' => 170)
); $person = my_sort($person, 'name', SORT_ASC, SORT_STRING); var_dump($person); ?>
结果
array (size=7)
0 =>
array (size=4)
'id' => int 4
'name' => string 'bill' (length=4)
'weight' => int 110
'height' => int 190
1 =>
array (size=4)
'id' => int 1
'name' => string 'fj' (length=2)
'weight' => int 100
'height' => int 180
2 =>
array (size=4)
'id' => int 3
'name' => string 'jerry' (length=5)
'weight' => int 120
'height' => int 156
3 =>
array (size=4)
'id' => int 7
'name' => string 'jordan' (length=6)
'weight' => int 70
'height' => int 170
4 =>
array (size=4)
'id' => int 5
'name' => string 'linken' (length=6)
'weight' => int 80
'height' => int 200
5 =>
array (size=4)
'id' => int 6
'name' => string 'madana' (length=6)
'weight' => int 95
'height' => int 110
6 =>
array (size=4)
'id' => int 2
'name' => string 'tom' (length=3)
'weight' => int 53
'height' => int 150
示例二:
<?php
$grade = array(
"score" => array(70, 95, 70.0, 60, "70"),
"name" => array("Zhang San", "Li Si", "Wang Wu", "Zhao Liu", "Liu Qi")
);
array_multisort($grade["score"], SORT_NUMERIC, SORT_DESC,
// 将分数作为数值,由高到低排序
$grade["name"], SORT_STRING, SORT_ASC);
// 将名字作为字符串,由小到大排序
var_dump($grade);
结果
array (size=2)
'score' =>
array (size=5)
0 => int 95
1 => string '70' (length=2)
2 => float 70
3 => int 70
4 => int 60
'name' =>
array (size=5)
0 => string 'Li Si' (length=5)
1 => string 'Liu Qi' (length=6)
2 => string 'Wang Wu' (length=7)
3 => string 'Zhang San' (length=9)
4 => string 'Zhao Liu' (length=8)
我看来,这算一个比较神奇的函数了
/* {{{ proto bool array_multisort(array ar1 [, SORT_ASC|SORT_DESC [, SORT_REGULAR|SORT_NUMERIC|SORT_STRING|SORT_NATURAL|SORT_FLAG_CASE]] [, array ar2 [, SORT_ASC|SORT_DESC [, SORT_REGULAR|SORT_NUMERIC|SORT_STRING|SORT_NATURAL|SORT_FLAG_CASE]], ...])
Sort multiple arrays at once similar to how ORDER BY clause works in SQL */
PHP_FUNCTION(array_multisort)
{
zval*** args;
zval*** arrays;
Bucket*** indirect;
Bucket* p;
HashTable* hash;
int argc;
int array_size;
int num_arrays = 0;
int parse_state[MULTISORT_LAST]; /* 0 - flag not allowed 1 - flag allowed */
int sort_order = PHP_SORT_ASC;
int sort_type = PHP_SORT_REGULAR;
int i, k; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
return;
} /* Allocate space for storing pointers to input arrays and sort flags. */
arrays = (zval ***)ecalloc(argc, sizeof(zval **));
for (i = 0; i < MULTISORT_LAST; i++) {
parse_state[i] = 0;
ARRAYG(multisort_flags)[i] = (int *)ecalloc(argc, sizeof(int));
} /* Here we go through the input arguments and parse them. Each one can
* be either an array or a sort flag which follows an array. If not
* specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
* accordingly. There can't be two sort flags of the same type after an
* array, and the very first argument has to be an array. */
for (i = 0; i < argc; i++) {
if (Z_TYPE_PP(args[i]) == IS_ARRAY) {
/* We see the next array, so we update the sort flags of
* the previous array and reset the sort flags. */
if (i > 0) {
ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type;
sort_order = PHP_SORT_ASC;
sort_type = PHP_SORT_REGULAR;
}
arrays[num_arrays++] = args[i]; /* Next one may be an array or a list of sort flags. */
for (k = 0; k < MULTISORT_LAST; k++) {
parse_state[k] = 1;
}
} else if (Z_TYPE_PP(args[i]) == IS_LONG) {
switch (Z_LVAL_PP(args[i]) & ~PHP_SORT_FLAG_CASE) {
case PHP_SORT_ASC:
case PHP_SORT_DESC:
/* flag allowed here */
if (parse_state[MULTISORT_ORDER] == 1) {
/* Save the flag and make sure then next arg is not the current flag. */
sort_order = Z_LVAL_PP(args[i]) == PHP_SORT_DESC ? -1 : 1;
parse_state[MULTISORT_ORDER] = 0;
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
MULTISORT_ABORT;
}
break; case PHP_SORT_REGULAR:
case PHP_SORT_NUMERIC:
case PHP_SORT_STRING:
case PHP_SORT_NATURAL:
#if HAVE_STRCOLL
case PHP_SORT_LOCALE_STRING:
#endif
/* flag allowed here */
if (parse_state[MULTISORT_TYPE] == 1) {
/* Save the flag and make sure then next arg is not the current flag. */
sort_type = Z_LVAL_PP(args[i]);
parse_state[MULTISORT_TYPE] = 0;
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
MULTISORT_ABORT;
}
break; default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is an unknown sort flag", i + 1);
MULTISORT_ABORT;
break; }
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or a sort flag", i + 1);
MULTISORT_ABORT;
}
}
/* Take care of the last array sort flags. */
ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays - 1] = sort_order;
ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays - 1] = sort_type; /* Make sure the arrays are of the same size. */
array_size = zend_hash_num_elements(Z_ARRVAL_PP(arrays[0]));
for (i = 0; i < num_arrays; i++) {
if (zend_hash_num_elements(Z_ARRVAL_PP(arrays[i])) != array_size) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array sizes are inconsistent");
MULTISORT_ABORT;
}
} /* If all arrays are empty we don't need to do anything. */
if (array_size < 1) {
for (k = 0; k < MULTISORT_LAST; k++) {
efree(ARRAYG(multisort_flags)[k]);
}
efree(arrays);
efree(args);
RETURN_TRUE;
} /* Create the indirection array. This array is of size MxN, where
* M is the number of entries in each input array and N is the number
* of the input arrays + 1. The last column is NULL to indicate the end
* of the row. */
indirect = (Bucket ***)safe_emalloc(array_size, sizeof(Bucket **), 0);
for (i = 0; i < array_size; i++) {
indirect[i] = (Bucket **)safe_emalloc((num_arrays + 1), sizeof(Bucket *), 0);
}
for (i = 0; i < num_arrays; i++) {
k = 0;
for (p = Z_ARRVAL_PP(arrays[i])->pListHead; p; p = p->pListNext, k++) {
indirect[k][i] = p;
}
}
for (k = 0; k < array_size; k++) {
indirect[k][num_arrays] = NULL;
} /* Do the actual sort magic - bada-bim, bada-boom. */
zend_qsort(indirect, array_size, sizeof(Bucket **), php_multisort_compare TSRMLS_CC); /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
HANDLE_BLOCK_INTERRUPTIONS();
for (i = 0; i < num_arrays; i++) {
hash = Z_ARRVAL_PP(arrays[i]);
hash->pListHead = indirect[0][i];;
hash->pListTail = NULL;
hash->pInternalPointer = hash->pListHead; for (k = 0; k < array_size; k++) {
if (hash->pListTail) {
hash->pListTail->pListNext = indirect[k][i];
}
indirect[k][i]->pListLast = hash->pListTail;
indirect[k][i]->pListNext = NULL;
hash->pListTail = indirect[k][i];
} p = hash->pListHead;
k = 0;
while (p != NULL) {
if (p->nKeyLength == 0)
p->h = k++;
p = p->pListNext;
}
hash->nNextFreeElement = array_size;
zend_hash_rehash(hash);
}
HANDLE_UNBLOCK_INTERRUPTIONS(); /* Clean up. */
for (i = 0; i < array_size; i++) {
efree(indirect[i]);
}
efree(indirect);
for (k = 0; k < MULTISORT_LAST; k++) {
efree(ARRAYG(multisort_flags)[k]);
}
efree(arrays);
efree(args);
RETURN_TRUE;
}
待续
参考:http://php.net/manual/zh/function.array-multisort.php
深入PHP内核之array_multisort的更多相关文章
- Linux 内核概述 - Linux Kernel
Linux 内核学习笔记整理. Unix unix 已有40历史,但计算机科学家仍认为其是现存操作系统中最大和最优秀的系统,它已成为一种传奇的存在,历经时间的考验却依然声名不坠. 1973 年,在用 ...
- [PHP内核探索]PHP中的哈希表
在PHP内核中,其中一个很重要的数据结构就是HashTable.我们常用的数组,在内核中就是用HashTable来实现.那么,PHP的HashTable是怎么实现的呢?最近在看HashTable的数据 ...
- QT5利用chromium内核与HTML页面交互
在QT5.4之前,做QT开发浏览器只能选择QWebkit,但是有过使用的都会发现,这个webkit不是出奇的慢,简直是慢的令人发指,Release模式下还行,debug下你就无语了,但是webkit毕 ...
- 模仿Linux内核kfifo实现的循环缓存
想实现个循环缓冲区(Circular Buffer),搜了些资料多数是基于循环队列的实现方式.使用一个变量存放缓冲区中的数据长度或者空出来一个空间来判断缓冲区是否满了.偶然间看到分析Linux内核的循 ...
- [内核笔记1]内核文件结构与缓存——inode和对应描述
由来:公司内部外网记录日志的方式现在都是通过Nginx模块收到数据发送到系统消息队列,然后由另外一个进程来从消息队列读取然后写回磁盘这样的操作,尽量的减少Nginx的阻塞. 但是由于System/V消 ...
- ucos实时操作系统学习笔记——内核结构和任务创建
对于ucos实时操作系统,邵贝贝的那本书已经写得很详细了,我因为之前不深的研究过ucos,所以在这里做一个笔记,写一些个人对该操作系统的理解,仅仅是个人理解,如果有人看到这边随笔有不对的地方,望给我指 ...
- linux内核调试技术之修改内核定时器来定位系统僵死问题
1.简介 在内核调试中,会经常出现内核僵死的问题,也就是发生死循环,内核不能产生调度.导致内核失去响应.这种情况下我们可以采用修改系统内核中的系统时钟的中断来定位发生僵死的进程和函数名称.因为内核系统 ...
- linux内核调试技术之自构proc
1.简介 在上一篇中,在内核中使用printk可以讲调试信息保存在log_buf缓冲区中,可以使用命令 #cat /proc/kmsg 将缓冲区的数区的数数据打印出来,今天我们就来研究一下,自己写k ...
- linux内核调试技术之printk
原创博客:欢迎转载,转载请注明出处https://i.cnblogs.com/EditPosts.aspx?postid=6218383 1.简介(基于s3c2440 linux) 在内核调试技术之中 ...
随机推荐
- 使用cxf开发webservice接口
项目中经常用到开发webservice接口,及调用webService接口.这里讲解如何使用cxf开发webService接口. 一.webservice介绍及理解 webservice是一种跨平台, ...
- Gson全解析(上)-Gson基础
前言 最近在研究Retrofit中使用的Gson的时候,发现对Gson的一些深层次的概念和使用比较模糊,所以这里做一个知识点的归纳整理. Gson(又称Google Gson)是Google公司发布的 ...
- pythonUnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe5 in position 108: ordinal not in range(128
今天做网页到了测试和数据库交互的地方,其中HTML和数据库都是设置成utf-8格式编码,插入到数据库中是正确的,但是当读取出来的时候就会出错,原因就是Python的str默认是ascii编码,和uni ...
- 【tyvj五月有奖赛 暨Loi 55 Round #1】
解题报告: 傻逼错误天天犯QAQ 第一题:简单DP,f[i][j]表示第 i 道题选 j 的最大得分,可以从f[i-1][j-1],f[i-1][j],f[i-1][j+1]转移过来,其实是可以滚动数 ...
- UVA 10012 How Big Is It?(暴力枚举)
How Big Is It? Ian's going to California, and he has to pack his things, including his collection ...
- Android -- 在ScrollView中嵌套ListView
在做一个工程,这个工程的布局可以相当的复杂,最外面是ScrollView,在ScrollView里面有两个Listview,这下好了,布局出来了,放在机子上跑,卡得想死有木有,信息乱跑乱出现,表示非常 ...
- 【SDN】SDN相关资料--了解一下电信领域的SDN
SDN相关资料 数据中心架构下ospf bgp如何选择及优缺点? - 数据中心 - 知乎 组播扩展OSPF_百度百科 carrier.huawei.com/cn/products/fixed-netw ...
- .NET-WEB网站部署的过程中需要注意的问题
--部署的网站的文件夹需要有IIS_USER权限(写权限) --部署的网站在外网不能访问:一般是由于防火墙的限制导致的.配置防火墙就可以.
- 【理解】column must appear in the GROUP BY clause or be used in an aggregate function
column "ms.xxx_time" must appear in the GROUP BY clause or be used in an aggregate functio ...
- [转] ssh免密码登录服务器
1. tencent 同事写的比较靠谱 https://www.chenyudong.com/archives/ssh-using-private-public-key-no-password.htm ...