前段时间和一个人聊天,聊到怎么用一个方法一次对两个数组取差集,我说使用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. KnockoutJS + My97DatePicker

    如何将Knockoutjs和其他脚本库结合使用?这里给出一个Knockoutjs与my97datepicker配合使用的例子,例子中使用了ko的自定义绑定功能: ko.bindingHandlers. ...

  2. 26、线性表(List)

    1.List List接口是Collection的子接口,List是一个可重复集合 2.ArrayList和LinkedList ArrayList和LinkedList是List接口最常见的两个实现 ...

  3. 最快下载速度100Mbps!4G LTE技术全解析

    1导读,关于4G的几个关键概念 [PConline资讯]100Mbps下载速度是什么概念?比3G网速快50倍又是什么概念?比3G通信方式更灵活.通信频谱更宽绰.通信质量更高效.通信费用更便宜是怎样一个 ...

  4. login.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  5. 转载:PHP JSON_ENCODE 不编码中文汉字的方法

    1.PHP版本5.4(包含)+ json_encode($data, JSON_UNESCAPED_UNICODE); //必须PHP5.4+ 2.PHP版本5.4- function encode_ ...

  6. JavaScript-jQuery报TypeError $(...) is null错误(jQuery失效)解决办法

    出现这种错误一般都是jQuery的$方法被覆盖, 解决办法: 1.把$改为jQuery使用 jQuery.noConflict();//将变量$的控制权让渡给给其他插件或库 jQuery(functi ...

  7. js 取值 getElementsByTagName,getElementsByName

    getElementsByTagName,getElementsByName  获取的值是数组的所以用[0][1]引用 1 <select multiple size="2" ...

  8. HDUOJ----The Number Off of FFF

    The Number Off of FFF Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  9. 【LeetCode】9. Palindrome Number (2 solutions)

    Palindrome Number Determine whether an integer is a palindrome. Do this without extra space. click t ...

  10. 重写lucene.net的分词器支持3.0.3.0版本

    lucene.net中每个分词器都是一个类,同时有一个辅助类,这个辅助类完成分词的大部分逻辑.分词类以Analyzer结尾,辅助类通常以Tokenizer结尾.分类词全部继承自Analyzer类,辅助 ...