PHP强化之03 - 数组 Array

—– 最后更新【2018-12-7】—–

一、语法

1、简介

PHP 中的数组实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字典,集合,栈,队列以及更多可能性。由于数组元素的值也可以是另一个数组,树形结构和多维数组也是允许的。

可以用 array()语言结构来新建一个数组。自 5.4 起可以使用短数组定义语法,用 [] 替代 array()。

$array = array(
    0 => "bar",
    1 => "foo"
);

// 自 PHP 5.4 起
$array = [
    0 => "bar",
    1 => "foo"
];

2、类型的转换

对于任意 integerfloatstringbooleanresource 类型,如果将一个值转换为数组,将得到一个仅有一个元素的数组,其下标为 0,该元素即为此标量的值。换句话说,(array) $scalarValuearray($scalarValue) 完全一样。

如果一个 object 类型转换为 array,则结果为一个数组,其单元为该对象的属性,键名将为成员变量名。

将 NULL 转换为 array 会得到一个空的数组。

3、数组运算符

例子名称结果
$a + $b联合$a 和 $b 的联合。
$a == $b相等如果 $a 和 $b 具有相同的键/值对则为 TRUE。
$a === $b全等如果 $a 和 $b 具有相同的键/值对并且顺序和类型都相同则为 TRUE。
$a != $b不等如果 $a 不等于 $b 则为 TRUE。
$a <> $b不等如果 $a 不等于 $b 则为 TRUE。
$a !== $b不全等如果 $a 不全等于 $b 则为 TRUE。

+运算符把右边的数组元素附加到左边的数组后面,两个数组中都有的键名,则只用左边数组中的,右边的被忽略。

$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");

$c = $a + $b;
echo "Union of \$a and \$b: \n";
var_dump($c);

执行结果:

Union of $a and $b: 
array(3) {
  ["a"]=>
  string(5) "apple"
  ["b"]=>
  string(6) "banana"
  ["c"]=>
  string(6) "cherry"
}

数组中的单元如果具有相同的键名和值则比较时相等。

$a = array("apple", "banana");
$b = array(1 => "banana", "0" => "apple");

var_dump($a == $b); // bool(true)
var_dump($a === $b); // bool(false)

二、常用方法

1、对数组进行排序

函数名称排序依据数组索引键保持排序的顺序
array_multisort()键值关联的保持,数字类型的不保持第一个数组或者由选项指定
asort()由低到高
arsort()由高到低
krsort()由高到低
ksort()由低到高
natcasesort()自然排序,大小写不敏感
natsort()自然排序
rsort()由高到低
shuffle()随机
sort()由低到高
uasort()由用户定义
uksort()由用户定义
usort()由用户定义

注意:以上的所有排序函数都是直接作用于数组本身, 而不是返回一个新的有序的数组。

相关函数:
shuffle() — 打乱数组

2、数组与字符串间的转换

1)implode – 将一个一维数组的值转化为字符串

string implode ( string $glue , array $pieces )
string implode ( array $pieces )

join — 别名 implode()

2)explode — 使用一个字符串分割另一个字符串

array explode ( string $delimiter , string $string [, int $limit ] )

3)preg_split — 通过一个正则表达式分隔字符串

array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )

3、数组的运算

1)array_merge — 合并一个或多个数组

array array_merge ( array $array1 [, array $... ] )

array_merge() 将一个或多个数组的单元合并起来,一个数组中的值附加在前一个数组的后面。返回作为结果的数组。

如果输入的数组中有相同的字符串键名,则该键名后面的值将覆盖前一个值。然而,如果数组包含数字键名,后面的值将不会覆盖原来的值,而是附加到后面。

如果只给了一个数组并且该数组是数字索引的,则键名会以连续方式重新索引

$array1 = array("color" => "red", 2, 4);
$array2 = array("a", "b", "color" => "green", "shape" => "trapezoid", 4);
$result = array_merge($array1, $array2);
print_r($result);

//以上例程会输出:
Array
(
    [color] => green
    [0] => 2
    [1] => 4
    [2] => a
    [3] => b
    [shape] => trapezoid
    [4] => 4
)

计算并集:

// 计算数组$a与数组$b的并集
$union = array_unique(array_merge($a, $b))

如果你想完全保留原有数组并只想新的数组附加到后面,则可用 + 运算符。

2)array_intersect — 计算数组的交集

array array_intersect ( array $array1 , array $array2 [, array $... ] )

返回一个数组,该数组包含了所有在 array1 中也同时出现在所有其它参数数组中的值。

$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_intersect($array1, $array2);
print_r($result);

// 以上例程会输出:
Array
(
    [a] => green
    [0] => red
)

3)array_diff — 计算数组的差集

array array_diff ( array $array1 , array $array2 [, array $... ] )

返回一个数组,该数组包括了所有在 array1 中但是不在任何其它参数数组中的值。注意键名保留不变。

如果需要得出简单差集,可以通过如下方法:

$difference = array_merge(array_diff($a, $b), array_diff($b, $a));

4)array_push — 将一个或多个单元压入数组的末尾(入栈)

int array_push ( array &$array , mixed $value1 [, mixed $... ] )

array_push() 将 array 当成一个栈,并将传入的变量压入 array 的末尾。array 的长度将根据入栈变量的数目增加。和$array[] = $var;效果相同。

Note: 如果用 array_push() 来给数组增加一个单元,还不如用 $array[] = ,因为这样没有调用函数的额外负担。
Note: 如果第一个参数不是数组,array_push() 将发出一条警告。这和 $var[] 的行为不同,后者会新建一个数组。

5)array_pop — 弹出数组最后一个单元(出栈)

mixed array_pop ( array &$array )

array_pop() 弹出并返回 array 数组的最后一个单元,并将数组 array 的长度减一。

6)array_pad — 以指定长度将一个值填充进数组

array array_pad ( array $array , int $size , mixed $value )

array_pad() 返回 array 的一个拷贝,并用 value 将其填补到 size 指定的长度。如果 size 为正,则填补到数组的右侧,如果为负则从左侧开始填补。如果 size 的绝对值小于或等于 array 数组的长度则没有任何填补。有可能一次最多填补 1048576 个单元。

$input = array(12, 10, 9);

$result = array_pad($input, 5, 0);
// result is array(12, 10, 9, 0, 0)

7)list — 把数组中的值赋给一组变量

array list ( mixed $var1 [, mixed $... ] )

像 array() 一样,list()不是真正的函数,而是语言结构。 list() 可以在单次操作内就为一组变量赋值。

$info = array('coffee', 'brown', 'caffeine');
// 列出所有变量
list($drink, $color, $power) = $info;
echo "$drink is $color and $power makes it special.\n";
// 列出他们的其中一个
list($drink, , $power) = $info;
echo "$drink has $power.\n";

相关方法:
split — 用正则表达式将字符串分割到数组中
str_split — 将字符串转换为数组

4、数组的内部指针

1)reset — 将数组的内部指针指向第一个单元

mixed reset ( array &$array )

reset() 将 array 的内部指针倒回到第一个单元并返回第一个数组单元的值。

$array = array('step one', 'step two', 'step three', 'step four');

echo current($array) . "<br />"; // "step one"

// skip two steps
next($array);
next($array);
echo current($array) . "<br />"; // "step three"

// reset pointer, start again on step one
reset($array);
echo current($array) . "<br />"; // "step one"

相关函数:
end() — 将 array 的内部指针移动到最后一个单元并返回其值

2)current — 返回数组中的当前单元

mixed current ( array &$array )

每个数组中都有一个内部的指针指向它”当前的”单元,初始指向插入到数组中的第一个单元。
注意:current() 函数返回当前被内部指针指向的数组单元的值,并不移动指针。如果内部指针指向超出了单元列表的末端,current() 返回 FALSE。

相关函数:
key() — 函数返回数组中内部指针指向的当前单元的键名。 但它不会移动指针。如果内部指针超过了元素列表尾部,或者数组是空的,key() 会返回 NULL。

3)next — 将数组中的内部指针向前移动一位

mixed next ( array &$array )

next() 和 current() 的行为类似,只有一点区别,在返回值之前将内部指针向前移动一位。这意味着它返回的是下一个数组单元的值并将数组指针向前移动了一位。
相关函数:
prev() — 返回数组内部指针指向的前一个单元的值,或当没有更多单元时返回 FALSE。

4)each — 返回数组中当前的键/值对并将数组指针向前移动一步

array each ( array &$array )

在执行 each() 之后,数组指针将停留在数组中的下一个单元或者当碰到数组结尾时停留在最后一个单元。如果要再用 each 遍历数组,必须使用 reset()。

如果内部指针越过了数组的末端,则 each() 返回 FALSE。

$foo = array("Robert" => "Bob", "Seppo" => "Sepi");
$bar = each($foo);
print_r($bar);

//输出结果如下:
Array
(
    [1] => Bob
    [value] => Bob
    [0] => Robert
    [key] => Robert
)

5、回调函数的应用

1)array_map — 为数组的每个元素应用回调函数

array array_map ( callable $callback , array $array1 [, array $... ] )

array_map():返回数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。

function cube($n) {
    return ($n * $n * $n);
}
$a = array(1, 2, 3, 4, 5);
$b = array_map("cube", $a);
print_r($b);

//结果如下:
Array
(
    [0] => 1
    [1] => 8
    [2] => 27
    [3] => 64
    [4] => 125
)

注意:传入两个及以上的数组时,它们元素数量将会相同。因为回调函数会并行地处理相互对应的元素。 如果几个数组的元素数量不一致:空元素会扩展短那个数组,直到长度和最长的数组一样。

2)array_filter — 用回调函数过滤数组中的单元

array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )

依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。

如果没有提供 callback 函数, 将删除 array 中所有等值为 FALSE 的条目。

function odd($var) {
    // 奇数会返回1,偶数会返回0
    return($var & 1);
}
function even($var) {
    return(!($var & 1));
}

$array1 = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);

echo "Odd :\n";
print_r(array_filter($array1, "odd"));
echo "Even:\n";
print_r(array_filter($array2, "even"));

//以上例程会输出:
Odd :
Array
(
    [a] => 1
    [c] => 3
    [e] => 5
)
Even:
Array
(
    [0] => 6
    [2] => 8
    [4] => 10
    [6] => 12
)

callback 函数对于想保留的值返回true,对于不想保留的值返回false。

相关函数:
array_unique() — 移除数组中重复的值

3)array_walk — 使用用户自定义函数对数组中的每个元素做回调处理

bool array_walk ( array &$array , callable $callback [, mixed $userdata = NULL ] )

成功时返回 TRUE, 或者在失败时返回 FALSE。

Note: 如果 callback 需要直接作用于数组中的值,则给 callback 的第一个参数指定为引用。这样任何对这些单元的改变也将会改变原始数组本身。

$fruits = array("d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple");

function test_alter(&$item1, $key, $prefix) {
    $item1 = "$prefix: $item1";
}

function test_print($item2, $key) {
    echo "$key. $item2<br />\n";
}

echo "Before ...:\n";
array_walk($fruits, 'test_print');
array_walk($fruits, 'test_alter', 'fruit');

echo "... and after:\n";
array_walk($fruits, 'test_print');
?>  

// 以上例程会输出:
Before ...:
d. lemon
a. orange
b. banana
c. apple
... and after:
d. fruit: lemon
a. fruit: orange
b. fruit: banana
c. fruit: apple

相关函数:
array_walk_recursive() — 对数组中的每个成员递归地应用用户函数。array_walk_recursive函数只将非数组元素传递到回调函数,所以从array_walk切换时不需要修改回调。

6、数组的键与值

1)array_values — 返回数组中所有的值并给其建立数字索引

array array_values ( array $array )
$array = array("size" => "XL", "color" => "gold");
print_r(array_values($array));

//上例会输出:
Array
(
    [0] => XL
    [1] => gold
)

2)array_keys — 返回数组中部分的或所有的键名

array array_keys ( array $array [, mixed $search_value = null [, bool $strict = false ]] )

如果指定了可选参数 search_value,则只返回该值的键名。否则 input 数组中的所有键名都会被返回。

$array = array(0 => 100, "color" => "red");
print_r(array_keys($array));

$array = array("blue", "red", "green", "blue", "blue");
print_r(array_keys($array, "blue"));

// 以上例程会输出:
Array
(
    [0] => 0
    [1] => color
)
Array
(
    [0] => 0
    [1] => 3
    [2] => 4
)

3)array_search — 在数组中搜索给定的值,如果成功则返回首个相应的键名

mixed array_search ( mixed $needle , array $haystack [, bool $strict = false ] )

大海捞针,在大海(haystack)中搜索针( needle 参数)。

如果 needlehaystack 中出现不止一次,则返回第一个匹配的键。要返回所有匹配值的键,应该用 array_keys() 加上可选参数 search_value 来代替。

$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array);   // $key = 2;

4)array_key_exists — 检查数组里是否有指定的键名或索引

bool array_key_exists ( mixed $key , array $array )

array_key_exists() 仅仅搜索第一维的键。 多维数组里嵌套的键不会被搜索到。

$search_array = array('first' => 1, 'second' => 4);
if (array_key_exists('first', $search_array)) {
    echo "The 'first' element is in the array";
}

相关函数:
in_array() — 检查数组中是否存在某个值

7、数组的遍历

1)for循环
适用情况,数组的下标为从0开始的连续索引。

$arr = ['a','b','c','d','e','f','g'];
$count = count($arr);
for($i = 0; $i < $count; $i++){
  echo $arr[$i] . "<br />";
}

2)foreach循环
foreach为php遍历数组最常用的方法。

$arr = array( 12, 'a'=>8, 6=>10, 'b'=> 3, 80);
foreach($arr as $k=>$v){
        echo "$k: $v <br>";
}

3)while、list()、each()组合循环

$arr = array( 12, 'a'=>8, 6=>10, 'b'=> 3, 80);
while(list($key,$val) = each($arr)){
  echo "$key: $val <br />";
}

//运行结果如下:
0: 12 
a: 8 
6: 10 
b: 3 
7: 80

注意:由于list方法的不确定性,不建议使用该方法遍历数组,了解一下即可。

4)三种遍历方式的区别

  • for循环只能遍历索引数组
  • foreach可以遍历索引和关联数组
  • while、list()、each()组合循环同样可以遍历索引和关联数组
  • while、list()、each()组合不会reset()
  • foreach遍历会对数组进行reset()操作

5)for、next()、key()、current()组合

$arr = array( 12, 'a'=>8, 6=>10, 'b'=> 3, 80);
$count = count($arr);
for($i=0; $i<$count;$i++){
  $key = key($arr);
  $val = current($arr);
  echo "$key: $val <br />";
  next($arr);
}

//运行结果如下:
0: 12 
a: 8 
6: 10 
b: 3 
7: 80

//注意,当循环结束后如果再去获取key和val,将不会成功,如:
$key = key($arr);
$val = current($arr);
var_dump($key,$val);   //结果为:NILL、bool(false)

三、经典实例

1、根据父ID获取所有下级的子ID(子ID下面上可能还有子ID))

//测试数据
$data = [
        0=>['id'=>1,'name'=>'zhuangsan','pid'=>4],
        1=>['id'=>2,'name'=>'zhuangsan','pid'=>3],
        2=>['id'=>3,'name'=>'zhuangsan','pid'=>4],
        3=>['id'=>4,'name'=>'zhuangsan','pid'=>6],
        4=>['id'=>5,'name'=>'zhuangsan','pid'=>2],
        5=>['id'=>6,'name'=>'zhuangsan','pid'=>9]
];

/**
 * 递归获取所有子id
 * @param $data 数据集
 * @param $pid 父id
 */
function select_tree($data,$pid){
    static $treeid = array();
    foreach($data as $key=>$val){
        if($pid==$val['pid']){
            $treeid[] = $val['id'];
            select_tree($data,$val['id']);
        }     
    }
    return $treeid;
}

$res = select_tree($data,4);
var_dump($res); 

//运行结果:
root@Chan:~$ php demo11.php
array(4) {
  [0] =>
  int(1)
  [1] =>
  int(3)
  [2] =>
  int(2)
  [3] =>
  int(5)
}

注意: 此类型题数据中不允许出现层级循环,否则该递归方法将出现死循环,程序报错!
扩展: 要求不使用递归,写出一个解决上题的方法。

2、写一个函数,要求不使用array_merge完成多个数组的合并

$arr1 = ['2'=>'no',5=>100,3];
$arr2 = [1,2,3];
$arr3 = [1=>'a','b','c'];
function array_mer(){
        $return = [];
        $arrays = func_get_args();
        foreach($arrays as $arr){
                foreach($arr as $v){
                        $return[] = $v;
                }
        }
        return $return;
}
$arr = array_mer($arr1,$arr2,$arr3);
var_dump($arr);

结果如下(与array_merge函数返回的结果一样):

array (size=9)
  0 => string 'no' (length=2)
  1 => int 100
  2 => int 3
  3 => int 1
  4 => int 2
  5 => int 3
  6 => string 'a' (length=1)
  7 => string 'b' (length=1)
  8 => string 'c' (length=1)

参考:

1、官方文档:

2、相关书籍:

  • 《PHP经典实例》 David Sklar & Adam Trachtenberg
    原文作者:Nosee123
    原文地址: https://www.jianshu.com/p/8aa77f5ce94f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞