前段时间和一个人聊天,聊到怎么用一个方法一次对两个数组取差集,我说使用array_diff倒是可以做到这个,但是不能只用一次,得两次。然后他就开始跟我讲他理解的array_diff的底层原理:“首先php会对两个数组取交集,然后会把两个数组中不属于交集的元素全部返回,所以只需要一次就够了,根本不用两次”。

说实话,我也希望是这样,但是事实不是这样,以下是php(php-7.0.7)的源码

PHP_FUNCTION(array_diff)
{
zval *args;
int argc, i;
uint32_t num;
HashTable exclude;
zval *value;
zend_string *str, *key;
zend_long idx;
zval dummy; /* 判断参数个数是否合法 */
if (ZEND_NUM_ARGS() < 2) {
php_error_docref(NULL, E_WARNING, "at least 2 parameters are required, %d given", ZEND_NUM_ARGS());
return;
} /* */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
return;
} if (Z_TYPE(args[0]) != IS_ARRAY) {
php_error_docref(NULL, E_WARNING, "Argument #1 is not an array");
RETURN_NULL();
} /* count number of elements */
num = 0;
for (i = 1; i < argc; i++) {
if (Z_TYPE(args[i]) != IS_ARRAY) {
php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1);
RETURN_NULL();
}
num += zend_hash_num_elements(Z_ARRVAL(args[i]));
} if (num == 0) {
ZVAL_COPY(return_value, &args[0]);
return;
} ZVAL_NULL(&dummy);
/* create exclude map */
/* 初始化exclude */
zend_hash_init(&exclude, num, NULL, NULL, 0);
/* 从第二个参数开始遍历参数列表,将各个数组中的元素(element)依次添加到exclude中 */
for (i = 1; i < argc; i++) {
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) {
str = zval_get_string(value);
zend_hash_add(&exclude, str, &dummy);
zend_string_release(str);
} ZEND_HASH_FOREACH_END();
} /* copy all elements of first array that are not in exclude set */
/* 将包含在第一个数组中但不在exclude中的元素(elements)复制到return_value中 */
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(args[0]), idx, key, value) {
str = zval_get_string(value);
if (!zend_hash_exists(&exclude, str)) {
if (key) {
value = zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
} else {
value = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, value);
}
zval_add_ref(value);
}
zend_string_release(str);
} ZEND_HASH_FOREACH_END(); zend_hash_destroy(&exclude);
}

过程描述:

  1.计算除了第一个数组之外的数组的元素个数;

  2.初始化HashTable exclude,大小就是第一步计算的元素个数的大小;

  3.把除了第一个数组之外的数组元素全部放到exclude中;

  4.然后用zend_hash_exists方法将第一个数组args[0]的元素和exclude中的元素一一比较,如果发现有元素不在exclude中就把这个元素放到return_value中,直到把args[0]中的元素遍历一遍。

到这个时候return_value中存的数据就array_diff返回给用户的数据。

以上就是array_diff的运行原理,不存在数组取交集的过程,每次调用array_diff得到的结果都是第一个数组中存在但是后面数组中均不存在的元素的集合。

绿色部分才是array_diff(array1,array2, array3,...,arrayN);的结果。

php array_diff分析的更多相关文章

  1. php内置函数分析array_diff()

    PHP_FUNCTION(array_diff) { zval *args; int argc, i; uint32_t num; HashTable exclude; zval *value; ze ...

  2. PHP:第四章——PHP数组array_diff计算数组差集

    <pre> <?php header("Content-Type:text/html;charset=utf-8"); /*知识点一:array_diff — 计 ...

  3. Joomla 3.9.13 二次注入分析(CVE-2019-19846)

    目录 前言 分析 更好的注入 利用 总结 补丁分析 前言 这一个需要管理员权限的二次SQL注入,利用起来比较鸡肋.这里仅分享一下挖洞时的思路,不包含具体的poc. 分析 漏洞触发点在component ...

  4. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  5. 火焰图分析openresty性能瓶颈

    注:本文操作基于CentOS 系统 准备工作 用wget从https://sourceware.org/systemtap/ftp/releases/下载最新版的systemtap.tar.gz压缩包 ...

  6. 一起来玩echarts系列(一)------箱线图的分析与绘制

    一.箱线图 Box-plot 箱线图一般被用作显示数据分散情况.具体是计算一组数据的中位数.25%分位数.75%分位数.上边界.下边界,来将数据从大到小排列,直观展示数据整体的分布情况. 大部分正常数 ...

  7. 应用工具 .NET Portability Analyzer 分析迁移dotnet core

    大多数开发人员更喜欢一次性编写好业务逻辑代码,以后再重用这些代码.与构建不同的应用以面向多个平台相比,这种方法更加容易.如果您创建与 .NET Core 兼容的.NET 标准库,那么现在比以往任何时候 ...

  8. UWP中新加的数据绑定方式x:Bind分析总结

    UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...

  9. 查看w3wp进程占用的内存及.NET内存泄露,死锁分析

    一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...

随机推荐

  1. 继承Spring AbstractRoutingDataSource实现路由切换

    继承Spring AbstractRoutingDataSource实现路由切换 原创 2016年05月11日 16:50:08 标签: mybatis / AbstractRoutingDataS  ...

  2. js setInterval() 用法示例

      Created by Marydon on 1.定义 语法:setInterval(param1,param2) param1 要调用的函数或要执行的代码串. param2 周期性调用param1 ...

  3. 如何从maven资源库下载jar包

      如何从maven资源库下载jar包 CreationTime--2018年6月7日09点00分 Author:Marydon 一.前提 需要安装并配置maven环境 二.准备工作 1.在桌面创建一 ...

  4. 〖Linux〗build ssh for Arm

    1. 交叉编译环境: export ARCH=arm export SUBARCH=arm export PATH=/opt/FriendlyARM/toolschain//bin:$PATH exp ...

  5. js 展开/收起效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. JNI 在命令行窗口输入字符,不显所输入字符,显指定的掩饰符

    //JNI-命令行窗口输入字符,显掩饰符.txt /*  目标:在命令行窗口输入字符,不显所输入字符,显指定的掩饰符  作者:tangshancheng@21cn.com*/ 1.KeyBoard.j ...

  7. 学习KNN

    转:© 著作权归作者所有 by ido 什么是KNN算法呢?顾名思义,就是K-Nearest neighbors Algorithms的简称.我们可能都知道最近邻算法,它就是KNN算法在k=1时的特例 ...

  8. HDUOJ---1754 I Hate It (线段树之单点更新查区间最大值)

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  9. HDUOJ----旋转的二进制

    旋转的二进制 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submis ...

  10. bootstrap Validators

    地址:http://reactiveraven.github.io/jqBootstrapValidation/