妙用PHP函数处理数组
PHP的数组是一种很强大的数据类型,与此同时PHP内置了一系列与数组相关的函数可以轻松地实现日常开发功能。
1. 取数组指定键名列
对于某些关联数组,有时候我们只想取指定键名的那部分,比如数组为 ['id' => 1, 'name' => 'zane', 'password' => '123456'] 此时若只想取包含 id 和 name 的部分该怎么实现呢?
<?php
$raw = ['id' => 1, 'name' => 'zane', 'password' => '123456'];
// 自己用PHP实现的函数
function onlyKeys($raw, $keys) {
$new = [];
foreach ($raw as $key => $val) {
if (in_array($key, $keys)) {
$new[$key] = $val;
}
} return $new;
}
// 用PHP内置函数实现
function newOnlyKeys($array, $keys) {
return array_intersect_key($array, array_flip($keys));
}
// 开始调用
var_dump(onlyKeys($raw, ['id', 'name']));
// 结果 ['id' => 1, 'name' => 'zane']
var_dump(newOnlyKeys($raw, ['id', 'name']));
// 结果 ['id' => 1, 'name' => 'zane']
这里简单的介绍一下这两个函数的作用,首先是 array_flip 函数,这个函数的功能是「将数组的键和值对调」,也就是键名变成值,值变成键名。我们传递的 $keys 参数经过这个函数便从 [0 => 'id', 1 => 'name'] 转变为了 ['id' => 0, 'name' => 1]。
这样做的目的是为了向 array_intersect_key 函数服务,array_intersect_key 函数的功能是「使用键名比较计算数组的交集」,也就是返回第一个参数数组中与其他参数数组相同键名的值。
这样便实现了取指定键名的功能
2. 移除数组中指定键名
有了上一个例子做铺垫,这个就很简单了
<?php
$raw = ['id' => 1, 'name' => 'zane', 'password' => '123456'];
// 用PHP内置函数实现
function removeKeys($array, $keys) {
return array_diff_key($array, array_flip($keys));
}
// 移除 id 键
var_dump(removeKeys($raw, ['id', 'password']));
// 结果 ['name' => 'zane']
和上一个例子相比本例只是将 array_intersect_key 函数改为 array_diff_key,这个函数的功能「使用键名比较计算数组的差集」,刚好和 array_intersect_key 的功能相反而已。
3. 数组去重
PHP内置了array_unique函数
<?php
$input = ['you are' => 666, 'i am' => 233, 'he is' => 233, 'she is' => 666];
$result = array_unique($input);
var_dump($result);
// 结果 ['you are' => 666, 'i am' => 233]
用这个函数能解决大部分问题,但有时候会觉得它不够快,原因如下:
array_unique() 先将值作为字符串排序,然后对每个值只保留第一个遇到的键名,接着忽略所有后面的键名。
因为这个函数会先将数组进行排序,所以速度可能在某些场景达不到预期的要求。
这时候可以使用array_filp函数,这个函数的功能是「将数组的键和值对调」。试想一下我们连续调用两次 array_flip 函数是不是就相当于实现了 array_unique 函数的功能呢?
<?php
$input = ['you are' => 666, 'i am' => 233, 'he is' => 233, 'she is' => 666];
$result = array_flip(array_flip($input));
var_dump($result);
// 结果 ['she is' => 666, 'he is' => 233]
结果和 array_unique 的不一样!为什么,我们可以从 PHP 官方手册得到答案:
如果同一个值出现多次,则最后一个键名将作为它的值,其它键会被丢弃。
总的来说就是 array_unique 保留第一个出现的键名,array_flip 保留最后一个出现的键名。
注意:使用 array_flip 作为数组去重时数组的值必须能够作为键名(即为 string 类型或 integer 类型),否则这个值将被忽略。
4. 重置数组索引
当我们想要对一个索引并不连续的数组进行重置时,比如数组:[0 => 233, 99 => 666],对于这种数组我们只需要调用 array_values 函数即可实现。
<?php
$input = [0 => 233, 99 => 666];
var_dump(array_values($input));
// 结果 [0 => 233, 1 => 66]
需要注意的是 array_values 函数并不止重置数字索引还会将字符串键名也同样删除并重置。
那如何在保留字符串键名的同时重置数字索引呢?答案就是 array_slice 函数,代码示例如下:
<?php
$input = ['hello' => 'world', 0 => 233, 99 => 666];
var_dump(array_slice($input, 0));
// 结果 ['hello' => 'world', 0 => 233, 1 => 66]
array_slice 函数的功能是取出数组的中的一段,但它默认会重新排序并重置数组的数字索引,所以可以利用它重置数组中的数字索引。
5. 清除数组中空值
有时候我们想清除某个数组中的空值比如:null、false、0、0.0、[]空数组、''空字符串、'0'字符串0 ,这时 array_filter 函数便能帮上大忙。
<?php
$input = ['foo', false, -1, null, '', []];
var_dump(array_filter($input));
// 结果 [0 => 'foo', 2 => -1]
为什么会出现这样的结果呢?
array_filter 的作用其实是「用回调函数过滤数组中的单元」,它的第二个参数其实是个回调函数,向数组的每个成员都执行这个回调函数,若回调函数的返回值为 true 便保留这个成员,为 false 则忽略。
这个函数还有一个特性就是:
如果没有提供 callback 函数, 将删除 array 中所有等值为 FALSE 的条目。
等值为 false 就是转换为 bool 类型后值为 false 的意思,详细看文档:转换为布尔类型。
注意:如果不填写 callback 函数,0、0.0、'0'字符串0 这些可能有意义的值会被删除。所以如果清除的规则有所不同还需要自行编写 callback 函数。
6. 确定数组成员全部为真
有时候我们希望确认数组中的的值全部为 true,比如:
['read' => true, 'write' => true, 'execute' => true]
这时我们需要用一个循环判定吗?NO,NO,NO……只需要用 array_product 函数便可以实现了。
<?php
$power = ['read' => true, 'write' => true, 'execute' => true];
var_dump((bool)array_product($power));
// 结果 true
$power = ['read' => true, 'write' => true, 'execute' => false];
var_dump((bool)array_product($power));
// 结果 false
为什么能实现这个功能呢?
array_product 函数本来的功能是「计算数组中所有值的乘积」,在累乘数组中所有成员的时候会将成员的值转为数值类型。
当传递的参数为一个 bool 成员所组成的数组时,众所周知 true 会被转为 1,false 会被转为 0。然后只要数组中出现一个 false 累乘的结果自然会变成 0,然后我们再将结果转为 bool 类型不就是 false 了嘛!
注意:使用 array_product 函数将在计算过程中将数组成员转为数值类型进行计算,所以请确保你了解数组成员转为数值类型后的值,否则会产生意料之外的结果。
比如:
<?php
$power = ['read' => true, 'write' => true, 'execute' => 'true'];
var_dump((bool)array_product($power));
// 结果 false
上例是因为 'true' 在计算过程中被转为 0。
7. 获取数组指定键名之前或之后的数组
如果我们只想要关联数组中指定键名值之前的部分该怎么办呢?又用一个循环?
当然不用我们可以通过 array_keys、array_search 和 array_slice 组合使用便能够实现!
<?php
$data = ['first' => 1, 'second' => 2, 'third' => 3];
function beforeKey($array, $key) {
$keys = array_keys($array);
// $keys = [0 => 'first', 1 => 'second', 2 => 'third']
$len = array_search($key, $keys);
return array_slice($array, 0, $len);
}
var_dump(beforeKey($data, 'first'));
// 结果 []
var_dump(beforeKey($data, 'second'));
// 结果 ['first' => 1]
var_dump(beforeKey($data, 'third'));
// 结果 ['first' => 1, 'second' => 2]
思路解析,要实现这样的功能大部分同学都应该能想到 array_slice 函数,但这个函数取出部分数组是根据偏移量(可以理解为键名在数组中的顺序,从 0 开始)而不是根据键名的,而关联数组的键名却是是字符串或者是不按顺序的数字;
此时要解决的问题便是「如何取到键名对应的偏移量?」,这是 array_keys 函数便帮了我们大忙,它的功能是「返回数组中部分的或所有的键名」默认返回全部键名,此外返回的键名数组是以数字索引的,也就是说返回的键名数组的索引就是偏移量!
例子中的原数组变为:
[0 => 'first', 1 => 'second', 2 => 'third']
然后我们通过 array_search 便可以获得指定键名的偏移量了,因为这个函数的功能是「在数组中搜索给定的值,如果成功则返回首个相应的键名」。
有了偏移量我们直接调用 array_slice 函数便可以实现目的了。
上面的例子懂了,那获取指定键名之后的数组也就轻而易举了,略微修改 array_slice 即可。
<?php
$data = ['first' => 1, 'second' => 2, 'third' => 3];
function afterKey($array, $key) {
$keys = array_keys($array);
$offset = array_search($key, $keys);
return array_slice($array, $offset + 1);
}
var_dump(afterKey($data, 'first'));
// 结果 ['second' => 2, 'third' => 3]
var_dump(afterKey($data, 'second'));
// 结果 ['third' => 3]
var_dump(afterKey($data, 'third'));
// 结果 []
那如何获取指定值之前或之后的数组呢?
记得 array_search 的作用吧,其实我们只需要这样调用 beforeKey($data, array_search($value, $data)) 就实现了
8. 统计出数组中重复次数最多的值
假设有这样一个数组 [6, 11, 11, 2, 4, 4, 11, 6, 7, 4, 2, 11, 8],请问如何获取数组中重复次数最多的值?关键就在于 array_count_values 函数。
<?php
$data = [6, 11, 11, 2, 4, 4, 11, 6, 7, 4, 2, 11, 8];
$cv = array_count_values($data);
// $cv = [6 => 2, 11 => 4, 2 => 2, 4 => 3, 7 => 1, 8 => 1]
arsort($cv);
$max = key($cv);
var_dump($max);
// 结果 11
array_count_values 函数的功能是「统计数组中所有的值」,就是将原数组中的值作为返回数组的键名,值出现的次数作为返回数组的值。
这样我们便可以通过 arsort 函数对出现的次数进行降序排序并且保持索引关联。
最后使用 key 获得当前单元(当前单元默认为数组第一个成员)的键名,此时的键名即是原数组的值重复次数最多的值。
妙用PHP函数处理数组的更多相关文章
- 转:函数指针数组的妙用(I)
转自:http://blog.sina.com.cn/s/blog_4c78b35f010008hi.html 笔者在开发某软件过程中遇到这样一个问题,前级模块传给我二进制数据,输入参数为 char* ...
- C++基础——函数指针 函数指针数组
==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...
- typedef 函数指针 数组 std::function
1.整型指针 typedef int* PINT;或typedef int *PINT; 2.结构体 typedef struct { double data;}DATA, *PDATA; //D ...
- C++程序设计(关于函数中数组传递的一点心得)
题目: 10个学生考完期末考试评卷完成后,老师需要划出及格线,要求如下: (1) 及格线是10的倍数: (2) 保证至少有60%的学生及格: (3) 如果所有的学生都高于60分,则及格线为60分: ...
- C#委托与C语言函数指针及函数指针数组
C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用 ...
- PHP中使用数组指针函数操作数组示例
数组的内部指针是数组内部的组织机制,指向一个数组中的某个元素.默认是指向数组中第一个元素通过移动或改变指针的位置,可以访问数组中的任意元素.对于数组指针的控制PHP提供了以下几个内建函数可以利用. ★ ...
- C/C++ 一段代码区分数组指针|指针数组|函数指针|函数指针数组
#include<stdio.h> #include<stdlib.h> #include<windows.h> /* 举列子说明什么是函数指针 */ //以一个加 ...
- C/C++ 不带参数的回调函数 与 带参数的回调函数 函数指针数组 例子
先来不带参数的回调函数例子 #include <iostream> #include <windows.h> void printFunc() { std::cout<& ...
- c语言函数传递数组
1.传递数组,打印不出来 #include <stdio.h> void solve() { printf(]); } int main() { int i; ;i<n;i++) { ...
- Linux C 程序 函数,数组,指针,gdb调试器(SEVEN)
函数,数组,指针,gdb调试器 1.函数定义 如果明确指定返回类型,默认为int 参数传递:实参对形参的参数传递是单向的,实参只是把自己的值赋给形参. 形参的 ...
随机推荐
- JVM实战—3.JVM垃圾回收的算法和全流程
大纲 1.JVM内存中的对象何时会被垃圾回收 2.JVM中的垃圾回收算法及各算法的优劣 3.新生代和老年代的垃圾回收算法 4.避免本应进入S区的对象直接升入老年代 5.Stop the World问题 ...
- [转]OpenCV_Find Basis F-Matrix and computeCorrespondEpilines(获取一对图像的基础矩阵及对应极线)
代码如下: // BasisMatrixCalculate.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <ios ...
- 一种调试 线段树 / Treap / Splay / 左偏树 / LCT 等树形结构的技巧
前言 如果我们需要观察程序运行过程中,某一个变量.某一个序列的变化情况,你可以在修改的地方打断点 debug,或者直接在需要的地方输出就行了. 但是对于一些树形结构,我们不好将其直观地呈现出来,常常只 ...
- 测试直播伴侣和OBS对透明度的支持哪个好?
测试直播伴侣和OBS对透明度的支持哪个好? 抖音无人直播,用抖音弹幕助手 测试直播伴侣和OBS对透明度的支持哪个好?抖音无人直播,用抖音弹幕助手 测试地址1 测试地址2
- 引发类型为“System.Windows.Forms.AxHost+InvalidActiveXStateException”的异常 解决办法
出现题目的异常,多是引用第三方控件引起的. 在NEW时,需要初始化该对象. AxESACTIVEXLib.AxESActiveX ax = new AxESACTIVEXLib.AxESActiveX ...
- 单点登录-OAuth2
单点登录的实现原理 单点登录在现在的系统架构中广泛存在,他将多个子系统的认证体系打通,实现了一个入口多处使用,而在架构单点登录时,也会遇到一些小问题,在不同的应用环境中可以采用不同的单点登录实现方案来 ...
- linux安装软件配置
CentOS7更换yum为阿里源 1 备份本地源mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backu ...
- w3cschool-MyBatis 教程
参考 https://www.w3cschool.cn/mybatis/mybatis-dyr53b5w.html MyBatis 入门 SqlSessionFactoryBuilder用 SqlSe ...
- linux:lamp环境
关于LAMP LAMP搭建 安装php和Apache 先装php,因为安装php有apache的依赖包 yum install php 启动Apache service httpd start 启动成 ...
- NOIp 2024 考试策略
无论简不简单,都要在前 30min 浏览所有题面,思考哪题可做.哪题不可做,思考能打哪些部分分,9:00 再开始写 T1. 题目简单时 9:00 开写后,30min 以内切完 T1. 9:30 开 T ...