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

    在一个文档的state变化时,需要将变化情况告知关注用户,通过研究account.invoice的代码,发现是经过如下过程实现此功能的: 1.添加一个消息阶段: <record id=" ...

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

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

  3. 【Oracle】锁

    Oracle所有锁的分配和管理都是数据库管理系统自动完成的,不需要用户进行干预. v$lock表说明 字段 描述 ADDR Address of lock state object KADDR Add ...

  4. 二分查找法的C++泛型实现

    算法非常easy,直接贴代码啦 #include <iostream> using namespace std; template<typename T> int binary ...

  5. 利用ASP.NET一般处理程序动态生成Web图像(转)

    摘自:http://www.cnblogs.com/zhouhb/archive/2011/02/15/1955262.html 一般处理程序的扩展名为ashx,它实现了IHttpHandler接口, ...

  6. java 快速求素数

    package test ; import java.util.Scanner ; public class hello { public static void main(String [] arg ...

  7. DataSnap对象传递

    比较简单的方法: 1.引用DBXJSON,  DBXJSONReflect 假设有一个类: type TKid = class FirstName: String; LastName: String; ...

  8. Python实现 K_Means聚类算法

    使用 Python实现 K_Means聚类算法: 问题定义 聚类问题是数据挖掘的基本问题,它的本质是将n个数据对象划分为 k个聚类,以便使得所获得的聚类满足以下条件: 同一聚类中的数据对象相似度较高 ...

  9. 【LeetCode】52. N-Queens II

    N-Queens II Follow up for N-Queens problem. Now, instead outputting board configurations, return the ...

  10. C#委托、事件剖析(下)

    本节对事件进行总结. 二.事件: 1.概念:Event:A member that enables an object or class to provide notifications;官方的解释是 ...