【PHP小课堂】PHP中的数组函数学习(二)

PHP中的数组函数学习(二)

继续我们关于数组函数的学习。上篇文章中说过,数组在 PHP 中是一等一的公民,也是我们最常用的一种数据结构。对于大家来说,或许你还没有正式的学习过数据结构,但你一定听说过栈、队列这些名词,那么我们就先以数组中的队列、栈式操作为入口开始今天的内容。

队列、栈式操作

在数据结构的系列文章中,我们就说过数组可以代表顺序存储结构形式,所以,PHP 中也提供了非常方便的对于数组的一些算法操作,比如栈的操作。

go 复制代码
$arr = ['a', 'b'];

print_r(array_push($arr, 'c')); // 3
print_r($arr);
// Array
// (
//     [0] => a
//     [1] => b
//     [2] => c
// )

echo array_pop($arr), PHP_EOL; // c
print_r($arr);
// Array
// (
//     [0] => a
//     [1] => b
// )

通过 array_push() ,我们可以将一个元素压到数组的最后一位,就像压栈操作一样。而 array_pop() 则是获取并删除最后一个元素,这就像是我们的出栈操作一样。是不是非常地方便。当然,队列操作也有类似的功能,先来看看从数组的头部进行添加和删除元素的操作。

go 复制代码
echo array_unshift($arr, 'c'), PHP_EOL; // 3
print_r($arr);
// Array
// (
//     [0] => c
//     [1] => a
//     [2] => b
// )

echo array_shift($arr), PHP_EOL; // c
print_r($arr);
// Array
// (
//     [0] => a
//     [1] => b
// )

array_unshift() 用于将一个元素放到数组的最前面,对于数字下标的数组来说,其它原来存在的元素会依次向后移。array_shift() 则是从数组的顶部取出并删除一个元素。对于完善的队列操作来说,我们可以用 array_push() 入队,然后使用 array_shift() 出队,这就是一个非常典型的队列操作了。

array_push() 和 array_unshift() 函数也可以一次加入多个元素到数组中。

go 复制代码
array_push($arr, 'c', 'd', 'e');
print_r($arr);
// Array
// (
//     [0] => a
//     [1] => b
//     [2] => c
//     [3] => d
//     [4] => e
// )

当然,官方文档中其实不建议使用这个 array_push() ,因为我们可以直接使用 $arr[] = xxx; 这种形式来将数据添加到数组的末尾,同时,这样的语法还不需要经过函数调用,性能更好一些。当然,具体的选择还是要看我们的业务情况,这里也只是一个建议。

随机取出数组中的键

这里的随机取出来的是数组的键,也就是 key 的值,而不是数组的值。

go 复制代码
echo array_rand(['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c']); // 6

print_r(array_rand(['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'], 3));
// Array
// (
//     [0] => 0
//     [1] => baz
//     [2] => 6
// )

虽然 array_rand() 的名称会让人感觉是随机取出一个数组的值出来,但它确实只是随机的返回数组的键。如果给第二个参数赋值大于 1 的数字的话,那么它将返回的是一个数组,里面包含多个随机取得的键。

获取数组所有值的乘积

这个其实是一个聚合操作函数。就像 MySQL 中的 sum() 类似的功能,不过它可以获取数组中所有元素值的乘积。

go 复制代码
echo array_product([2,3,4]), PHP_EOL; // 24

echo array_product([2,3,'c']), PHP_EOL; // 0

echo array_product([]), PHP_EOL; // 1

需要注意的是,如果数组中包含字符串的话,那么返回的结果会是 0 。而如果是一个空数组的话,那么返回的是 1 。这一点是比较特殊的地方,照理说,如果有字符串存在它的计算结果应该和空数组是类似的才对,而且在老版本的 PHP 中确实空数组是返回的 0 ,但现在空数组返回的结果是 1 ,这一点大家一定要记清楚,免得在使用的时候因为这个问题而产生不可预知的 BUG 。

填补数组

这里的填补数组和我们上篇文章中的填充数组是有区别的。

go 复制代码
print_r(array_pad(['a', 'b'], 5, 'cc'));
// Array
// (
//     [0] => a
//     [1] => b
//     [2] => cc
//     [3] => cc
//     [4] => cc
// )

print_r(array_pad(['a', 'b'], -5, 'cc'));
// Array
// (
//     [0] => cc
//     [1] => cc
//     [2] => cc
//     [3] => a
//     [4] => b
// )

print_r(array_pad(['a', 'b'], 2, 'cc'));
// Array
// (
//     [0] => a
//     [1] => b
// )

array_fill() 一般是针对空的数组填充,用于数组的新建,而 array_pad() 一般是针对已经存在的数组进行填补。在上面的例子中,如果第二个参数是负数的话,就是从前面开始填补。如果这个参数和数组的数量一致或者小于数组的长度的话,那么就不会填补数据。

遍历数组

遍历数组的这个 array_map() 函数其实也是比较常见的一个函数。

go 复制代码
// 遍历数组
array_map(function($v){
    
    echo "元素值为:{$v} .", PHP_EOL;

}, ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c']);
// 元素值为:a .
// 元素值为:b .
// 元素值为:1 .
// 元素值为:2 .
// 元素值为:c .

其实它就是在回调函数中对每个元素进行遍历,我们可以在这个回调函数中对数组的所有数据进行一些操作。这个就不多说了,不过它还有更好玩的用法,比如我们可以同时操作多个数组。

go 复制代码
array_map(function($v1, $v2){
    
    echo "元素值为:{$v1}, {$v2} .", PHP_EOL;

}, ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'], ['d', 'e']);
// 元素值为:a, d .
// 元素值为:b, e .
// 元素值为:1,  .
// 元素值为:2,  .
// 元素值为:c,  .

它们的遍历操作是同时进行的,每多一个数组,这个回调函数就多一个参数,参数的内容就是数组的值。这个使用方式确实是平常没有注意到的,也是这次学习中发现的非常好玩的一点。

键操作

在数组中,键和值都是非常重要的数据内容。PHP 中为我们提供了丰富的专门针对键的操作函数,比如我们想获取一个数组中所有键的信息,就可以使用下面这个函数。

go 复制代码
print_r(array_keys(['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c']));
// Array
// (
//     [0] => 0
//     [1] => 1
//     [2] => foo
//     [3] => baz
//     [4] => 6
// )

array_keys() 返回的是一个包含指定数组中全部键信息的数组。它的使用比较简单,当然,我们也可以直接获取数组中指定位置的键信息。

go 复制代码
echo array_key_first(['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c']), PHP_EOL; // 0
echo array_key_last(['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c']), PHP_EOL; // 6

除了获取键的信息外,我们还可以判断数组中是否存在某个键,这个函数想必也是大家比较常见的。

go 复制代码
var_dump(array_key_exists('foo', ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'])); // bool(true)
var_dump(array_key_exists('foo1', ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'])); // bool(false)
var_dump(array_key_exists(6, ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'])); // bool(true)

var_dump(key_exists('foo', ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'])); // bool(true)

注意,key_exists() 和 array_key_exists() 是一样的,key_exists() 是 array_key_exists() 的一个别名函数。

go 复制代码
echo key(['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c']), PHP_EOL; // 0

key() 函数用于获取当前数组中当前游标位置的键值。这个是类似于游标操作的一个函数,所以我们可以配合其它游标操作函数来进行数组的遍历。

go 复制代码
$arr = ['a', 'b', 'foo' => 1, 'baz' => 2, 6 => 'c'];
while ($v = current($arr)) {
    echo key($arr), PHP_EOL;
    next($arr);
}
// 0
// 1
// foo
// baz
// 6

关于这种类似游标的操作,之前在关于让类可遍历的文章中也讲到过,其实 foreach() 的内部实现也是依赖于类似的这种游标循环操作。当然,在我们的现代化开发中,除了一些特殊情况之外,当然还是使用 foreach() 来得更加方便直观。

交集操作

最后就是我们的交集操作。上篇文章中我们已经学过了数组的差集的操作,今天的交集操作其实也是类似的,包括值的比对、键的比对、回调函数方式的函数这些,所以就不多做解释了,只是贴出代码大家自已运行测试一下。

go 复制代码
print_r(array_intersect(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x']));
// Array
// (
//     [1] => 1
//     [2] => b
//     [3] => c
//     [4] => x
// )

print_r(array_intersect_assoc(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x']));
// Array
// (
//     [4] => x
// )

print_r(array_intersect_key(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', 'x'], ['a', 'c', 'b', '1', 'x']));
// Array
// (
//     [0] => a
//     [1] => 1
//     [2] => b
//     [3] => c
// )

print_r(array_intersect_key(['a' => 1, 'b' => 2], ['b' => 3, 'd' => 4]));
// Array
// (
//     [b] => 2
// )

就和差集操作的函数名都带一个 diff 一样,交集操作的函数名都带一个 intersect 。大家只要记住这一块就可以了,其它的函数名称都和差集操作是类似的。

回调函数交集操作

同样的,带回调的操作函数也是类似的。

go 复制代码
print_r(array_intersect_uassoc(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x'], function ($a, $b) {
    return $a <=> $b;
}));
// Array
// (
//     [4] => x
// )

print_r(array_intersect_ukey(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x'], function ($a, $b) {
    return $a <=> $b;
}));
// Array
// (
//     [0] => a
//     [1] => 1
//     [2] => b
//     [3] => c
//     [4] => x
// )

print_r(array_uintersect(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x'], function ($a, $b) {
    return $a <=> $b;
}));
// Array
// (
//     [2] => b
//     [3] => c
//     [4] => x
// )

print_r(array_uintersect(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x'], function ($a, $b) {
    return $a <=> $b;
}));
// Array
// (
//     [2] => b
//     [3] => c
//     [4] => x
// )

print_r(array_uintersect_assoc(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x'], function ($a, $b) {
    return $a <=> $b;
}));
// Array
// (
//     [4] => x
// )

print_r(array_uintersect_uassoc(['a', 1, 'b', 'c', 'x'], ['b', 'c', 'd', '1', 'x'], ['a', 'c', 'b', '1', 'x'], function ($a, $b) {
    return $a <=> $b;
}, function ($a, $b) {
    return $a <=> $b;
}));
// Array
// (
//     [4] => x
// )

总结

今天学习的内容依然只是数组相关操作函数中的一小部分。我们了解到了一些数据结构相关操作函数的使用,也看到了交集操作的功能函数的应用。这些功能其实在我们日常的业务开发中还是挺常用的,比如在我做的统计系统中就经常会有交、差相关的操作,灵活使用这些函数能够大大方便我们的业务开发,大家可以多多深入研究好好掌握哦!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/04/source/1.PHP中的数组函数学习(二).php

参考文档:

https://www.php.net/manual/zh/ref.array.php

相关推荐
Scott9999HH4 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社5 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海5 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖6 小时前
JDK 26 新特性详解
java·开发语言
马优晨6 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a1117768 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao8 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
人邮异步社区8 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大9 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai9 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang