标题:【PHP小课堂】PHP中的数组函数学习(一)

文章目录
    分类:PHP 标签:PHP

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

    数组操作可是 PHP 中的重头戏,重头到什么地步呢?别的语言可以说是面向对象、面向过程,PHP 则可以完全说是面向数组的一种语言。它的各种数据结构到最后都可以用数组来表示,这就是很恐怖的一件事。因为不管什么操作,我们都可以以数组的形式操作,这样的话,这些数组操作相关的函数就会显得异常的强大。当然,这也和语言的发展特性分不开。


    从最开始,PHP 就只是一个准备服务于个人的小型网络编程语言。连作者都没想到它会发展成为 WEB 应用中的霸主级别的语言。为了更方便地使用,它摒弃了数据类型,也就是成为了动态语言。同时,在定义数组的时候,因为没有了数据类型的约束,所以它的数组定义也非常地方便。相信大家不管是从数据库中读取数据,还是操作远程数据,都会将数据转换成数组来操作。这也间接的成就了 PHP 中的数组特性,别的不说,就是方便。


    从这篇文章开始,我们就来好好地学习一下 PHP 中的数组相关的操作函数。学习的顺序是以官方文档中的函数列表顺序进行的。

    改变数组 KEY 的大小写

    首先我们来看一些简单的函数。第一个就是我们可以方便地转换数组键的大小写。

    $input_array = ['firST' => 1, 'SecOnd' => 2];
    
    print_r(array_change_key_case($input_array, CASE_UPPER));
    // Array
    // (
    //     [FIRST] => 1
    //     [SECOND] => 2
    // )
    
    print_r(array_change_key_case($input_array, CASE_LOWER));
    // Array
    // (
    //     [first] => 1
    //     [second] => 2
    // )
    
    print_r(array_change_key_case([10 => 1, '11' => 2], CASE_UPPER));
    // Array
    // (
    //     [10] => 1
    //     [11] => 2
    // )

    从函数名称就可以看出,array_change_key_case() 就是用于改变键的大小写的,它需要第二个参数,也就是一个常量参数,可以指定为 CASE_UPPER 大写以及 CASE_LOWER 小写。对于数字下标的键来说,它就没有什么效果了。

    分割数组

    分割数组的这个函数我们在之前的文章 PHP中的数组分页实现(非数据库)https://mp.weixin.qq.com/s/q3NcC-XoOEd3A1Vuqxdt8A 中已经学习过了。

    print_r(array_chunk(['a', 'b', 'c', 'd', 'e'], 2));
    // Array
    // (
    //     [0] => Array
    //         (
    //             [0] => a
    //             [1] => b
    //         )
    
    //     [1] => Array
    //         (
    //             [0] => c
    //             [1] => d
    //         )
    
    //     [2] => Array
    //         (
    //             [0] => e
    //         )
    
    // )
    
    print_r(array_chunk(['a', 'b', 'c', 'd', 'e'], 2, true));
    // Array
    // (
    //     [0] => Array
    //         (
    //             [0] => a
    //             [1] => b
    //         )
    
    //     [1] => Array
    //         (
    //             [2] => c
    //             [3] => d
    //         )
    
    //     [2] => Array
    //         (
    //             [4] => e
    //         )
    
    // )

    array_chunk() 函数用于将数组分割成我们指定的大小的多维数组,它还有第三个参数,如果指定为 true 的话,分割出来的小数组中的键会保留原来的键下标。

    获取数组中的某一个列值

    就像做 MySQL 查询时,我们可能只需要某一个列的数据。在对数组的操作时,我们也可以只获取数组中某一个键的内容。这个函数多用于二维数组。

    $records = [
        [
            'id' => 1,
            'username' => 'aaa',
            'password' => 'a1',
        ],
        [
            'id' => 2,
            'username' => 'bbb',
            'password' => 'b2',
        ],
        [
            'id' => 3,
            'username' => 'ccc',
            'password' => 'c3',
        ],
    ];
    
    print_r(array_column($records, 'username'));
    // Array
    // (
    //     [0] => aaa
    //     [1] => bbb
    //     [2] => ccc
    // )
    
    print_r(array_column($records, 'username', 'id'));
    // Array
    // (
    //     [1] => aaa
    //     [2] => bbb
    //     [3] => ccc
    // )

    在例子中,我们只需要数据中的 username 属性的内容。array_column() 如果不指定第三个参数的话,就会以普通数字下标的形式抽取指定第二维数组中的需要的键值。如果指定了第三个参数,就会将第三个参数当做新的数组的键。这个函数也是支持从对象中抽取数据的。

    class User
    {
        public function __construct($id, $username, $password)
        {
            $this->id = $id;
            $this->username = $username;
            $this->password = $password;
        }
    }
    
    $users = [
        new User(1, 'aaa', 'a1'),
        new User(2, 'bbb', 'b2'),
        new User(3, 'ccc', 'c3'),
    ];
    
    print_r(array_column($users, 'password', 'username'));
    // Array
    // (
    //     [aaa] => a1
    //     [bbb] => b2
    //     [ccc] => c3
    // )

    array_column() 的应用场景还是比较多的,比如我们经常会保存一些只是键值对形式的 Hash 数据在数据库中,而在日常的业务开发使用的时候需要从数据库拿出来并放到变量中形成 Hash 数组,这时就可以方便地使用 array_column() 实现。最常见的就是一些分类类型,比如用户组之类的数据。

    使用两个数组来创建一个新数组

    使用两个数组来创建一个新数组的意思就是让一个数组当键,一个数组当值。

    print_r(array_combine(['a', 'b', 'c', 'd', 'e'], [1, 2, 3, 4, 5]));
    // Array
    // (
    //     [a] => 1
    //     [b] => 2
    //     [c] => 3
    //     [d] => 4
    //     [e] => 5
    // )
    
    print_r(array_combine(['a', 'b', 'c', 'd'], [1, 2, 3, 4, 5]));
    // Warning: array_combine(): Both parameters should have an equal number of elements in /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/03/source/10.PHP中的数组函数学习(一).php on line 138

    两个数组的长度必须要一样的,如果长度不一样的话,就会报出一个警告信息。同时,也无法生成正式的数组。它对于二维数组的操作不太友好,也就是说,会将二维数组强转成一个字符串下标。

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

    注意看键,是一个 Array ,其实就是将它转换成了一个字符串。同时,第二个数组也只保留了其中的一个元素。

    填充创建数组

    填充数组的概念可以看作是我们指定数组的长度之后,使用固定的元素将这个数组填满。

    $a = array_fill(5, 6, 'banana');
    print_r($a);
    // Array
    // (
    //     [5] => banana
    //     [6] => banana
    //     [7] => banana
    //     [8] => banana
    //     [9] => banana
    //     [10] => banana
    // )

    注意它的第一个参数是开始填充的下标,第二个参数是填充的数量,第三个参数就是要填充的值。如果我们的下标是从小于 0 的下标开始的话,那么它的第一个元素会是这个负数的下标,而第二个元素就会从 0 开始。

    $b = array_fill(-2, 4, 'pear');
    print_r($b);
    // Array
    // (
    //     [-2] => pear
    //     [0] => pear
    //     [1] => pear
    //     [2] => pear
    // )

    另外,我们也可以通过另外一个函数来指定 key 进行填充。

    print_r(array_fill_keys(['foo', 5, 10, 'bar'], 'banana'));
    // Array
    // (
    //     [foo] => banana
    //     [5] => banana
    //     [10] => banana
    //     [bar] => banana
    // )

    数组中值的数量统计

    print_r(array_count_values([1,'a', 1, 'b', 1, 'a']));
    // Array
    // (
    //     [1] => 3
    //     [a] => 2
    //     [b] => 1
    // )
    
    print_r(array_count_values([['a', 'b'], ['c', 'd']]));
    // Warning: array_count_values(): Can only count STRING and INTEGER values! in /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/03/source/10.PHP中的数组函数学习(一).php on line 160
    // Array
    // (
    // )

    array_count_values() 只是统计值的数量。数组中是可以有重复的元素的,这个函数的作用就是统计这些元素在数组中出现的数量。不过从这里也可以看出,PHP 中的数组不是完全数学意义上的集合的概念。

    数组过滤

    数组过滤这个函数相信也有不少同学是经常使用的。

    print_r(array_filter([1,2,3,4,5,6,7, 0], function ($var){
        return $var%2==0;
    }));
    // Array
    // (
    //     [1] => 2
    //     [3] => 4
    //     [5] => 6
    //     [7] => 0
    // )

    像这个测试代码一样,我们可以方便地获取数组中的偶数数据。如果在回调函数中没有 return 的话,那么这个数据就不会返回到新的数组中,如果全部都不 return 的话,就会返回一个空的数组。另外,这个过滤用的回调函数也是可选的,如果不定义这个回调函数的,它会过滤空值,这个空值的范围是 null、0、空字符串 这些。

    rint_r(array_filter([1,2,3,4,5,6,7, 0]));
    // Array
    // (
    //     [0] => 1
    //     [1] => 2
    //     [2] => 3
    //     [3] => 4
    //     [4] => 5
    //     [5] => 6
    //     [6] => 7
    // )

    回调函数的参数是数组的值,它只能操作一维数组。

    print_r(array_filter([['a', 'b'], ['c', 'd'], []], function($var){
        print_r($var);
        return count($var)>0?:false;
    }));
    // Array
    // (
    //     [0] => a
    //     [1] => b
    // )
    // Array
    // (
    //     [0] => c
    //     [1] => d
    // )
    // Array
    // (
    // )
    // Array
    // (
    //     [0] => Array
    //         (
    //             [0] => a
    //             [1] => b
    //         )
    
    //     [1] => Array
    //         (
    //             [0] => c
    //             [1] => d
    //         )
    
    // )

    数组键值反转

    不少面试中会有面试官问到,如何反转一个数组的键值,也就是说,让一个数组的键变成值,值变成键。其实我们有现成的函数直接就可以实现。

    print_r(array_flip(["oranges", "apples", "pears"]));
    // Array
    // (
    //     [oranges] => 0
    //     [apples] => 1
    //     [pears] => 2
    // )
    
    print_r(array_flip(["a" => 1, "b" => 1, "c" => 2]));
    // Array
    // (
    //     [1] => b
    //     [2] => c
    // )

    使用这个 array_flip() 函数就可以实现键值的转换。数组的键是不能重复的,所以如果原来数组中的值有相同的元素,在转换之后,会使用最后一个数据覆盖。

    差值计算

    在数学中,集合的运算有交、并、差这些,今天我们先来接触一个差的运算。其实就是查找两个或多个数组中不同的数据,然后将这些不同的数据作为一个新的数组返回回来。

    print_r(array_diff(['a', 1, 'b', 'c', 'x'],['b', 'c', 'd'], ['a', 'c', 'e', '1']));
    // Array
    // (
    //     [3] => x
    // )

    普通的这个 array_diff() 函数是针对所有元素都会一一比较的。它也是以第一个参数中传递的数组为基准的,返回的是存在于第一个数组中,但在其它数组中不存在的数据。比如最后一个数组中有一个 e 元素在其它数组中是不存在的,但是并不会返回,只是以第一个数组为基准。


    除了所有元素的比较之外,还有一个函数可以根据键来比较,也就是说,必须键和值都对应上。

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

    array_diff_assoc() 返回的数组是除了 a 元素之外的数据,因为最后一个数组中的第一个元素也是 a ,它和第一个数组的中的 a 元素在键和值都对应上了。此外,还有专门针对键 key 的差计算操作函数 array_diff_key() 。

    print_r(array_diff_key(['a', 1, 'b', 'c', 'x'],['b', 'c', 'd'], ['a', 'c', 'e', '1']));
    // Array
    // (
    //     [4] => x
    // )
    
    print_r(array_diff_key(['b'=>2, 'a'=>1, 'c'=>3], ['a'=>2, 'b'=>3, 'cc'=>1]));
    // Array
    // (
    //     [c] => 3
    // )

    上述数组差值操作在非数字下标的数组中也都是可以使用的。

    使用回调函数进行差值计算

    差集计算的函数中,也提供了非常多的回调操作方式来让我们能够自定义的实现差值的计算。这个不仅是差集的计算,交、并计算中都有这种类似的使用回调函数进行计算的操作函数。最主要的原因也是为了方便我们能够根据业务情况进行各种自定义的计算开发。

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

    array_udiff() 的回调函数的参数是数组的值,分别是给定的数组里面值的相互比较,它需要返回一个值的计算大小,也就是大于、小于或等于。如果是等于的话,就说明这两个值是一样的,如果是大于或小于的话,就是这两个值之前的差值。这里我们使用的是 PHP7 的飞船运算符。对这个运算符号不了解的小伙伴可以自行查阅下相关的资料。


    在这个回调函数中,我们打印了 a 、 b 的内容,可以发现一个比较有意思的事情。第一个数组中的 1 和最后一个数组中的 "1" 没有比较。所以出来的结果差集有两个。而我们使用 array_diff() 函数的话,出来的结果差集只有一个 x 。

    print_r(array_udiff(['a', 1], ['a','1'], function($a, $b){
        var_dump($a);
        var_dump($b);
        echo $a, '===', $b, PHP_EOL;
        return $a <=> $b;
    }));
    // string(1) "a"
    // int(1)
    // a===1
    // string(1) "a"
    // string(1) "1"
    // a===1
    // string(1) "a"
    // string(1) "1"
    // a===1
    // string(1) "a"
    // string(1) "a"
    // a===a
    // string(1) "a"
    // int(1)
    // a===1
    // Array
    // (
    //     [1] => 1
    // )
    
    print_r(array_udiff(['a', '1'], ['a','1'], function($a, $b){
        var_dump($a);
        var_dump($b);
        echo $a, '===', $b, PHP_EOL;
        return $a <=> $b;
    }));
    // string(1) "a"
    // string(1) "1"
    // a===1
    // string(1) "a"
    // string(1) "1"
    // a===1
    // string(1) "1"
    // string(1) "1"
    // 1===1
    // string(1) "1"
    // string(1) "a"
    // 1===a
    // string(1) "a"
    // string(1) "a"
    // a===a
    // Array
    // (
    // )

    减少数据并且详细的测试之后会发现,如果两个元素的数据类型不相同,回调函数中都不会获得这两个元素的数据。大家可以自己测试一下,看看结果是不是和我这里一样的。


    同样的,和上面的普通差集函数一样,也可以根据对应的键值位置来比较。

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

    或者是根据键来比较。

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

    最后,还可以通过键和值一起使用两个不同的回调函数来进行差的运算。

    print_r(array_udiff_uassoc(['a', 1, 'b', 'c', 'x'],['b', 'c', 'd'], ['a', 'c', 'e', '1'], function($a, $b){
        echo 'value_compare_func: ', $a, '===', $b, PHP_EOL;
        return $a <=> $b;
    }, function($a, $b){
        echo 'key_compare_func: ', $a, '===', $b, PHP_EOL;
        return $a <=> $b;
    }));
    // key_compare_func: 0===1
    // key_compare_func: 1===2
    // key_compare_func: 2===3
    // key_compare_func: 3===4
    // key_compare_func: 0===1
    // key_compare_func: 1===2
    // key_compare_func: 0===1
    // key_compare_func: 1===2
    // key_compare_func: 2===3
    // key_compare_func: 0===0
    // value_compare_func: a===b
    // key_compare_func: 0===0
    // value_compare_func: a===a
    // key_compare_func: 1===0
    // key_compare_func: 1===1
    // value_compare_func: 1===c
    // key_compare_func: 1===0
    // key_compare_func: 1===1
    // value_compare_func: 1===c
    // key_compare_func: 2===0
    // key_compare_func: 2===1
    // key_compare_func: 2===2
    // value_compare_func: b===d
    // key_compare_func: 2===0
    // key_compare_func: 2===1
    // key_compare_func: 2===2
    // value_compare_func: b===e
    // key_compare_func: 3===0
    // key_compare_func: 3===1
    // key_compare_func: 3===2
    // key_compare_func: 3===0
    // key_compare_func: 3===1
    // key_compare_func: 3===2
    // key_compare_func: 3===3
    // value_compare_func: c===1
    // key_compare_func: 4===0
    // key_compare_func: 4===1
    // key_compare_func: 4===2
    // key_compare_func: 4===0
    // key_compare_func: 4===1
    // key_compare_func: 4===2
    // key_compare_func: 4===3
    // Array
    // (
    //     [1] => 1
    //     [2] => b
    //     [3] => c
    //     [4] => x
    // )

    怎么样,功能够丰富吧,这都是为我们开发者准备好的功能。在日常的业务开发中,大家可以选取合适的函数来方便地对数据进行相关的差集计算操作。

    总结

    今天入门并开始学习的一些数组函数都比较基础,交、并、差我们也学习了一个差集操作相关的内容。其它的交、并操作我们会在后面的文章中配合其它的数组函数一次讲解一个。毕竟这三个操作的函数非常多也非常的复杂,大家对于这三个操作的学习要更加的深入一些,平常多多用各种数据来练习吧。


    测试代码:


    https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/03/source/10.PHP%E4%B8%AD%E7%9A%84%E6%95%B0%E7%BB%84%E5%87%BD%E6%95%B0%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%B8%80%EF%BC%89.php


    参考文档:


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

    搜索
    关注