《Zend PHP 5 Certification》——数组
ZendChina官方:数组无疑是PHP里面的高级数据结构之王。PHP数组特别灵活 -- 可以储存数字,数组健,其他任何价值,以及其他数组。有超过70个内建数组函数。[b]数组基础[/b]
所有数组都是元素按顺序组成的。每个元素有一个值,有一个唯一可证实的键。键可以是数字,也可以是字串。
数组有两种方式来建立。一种是用array()的方式,如:
[color=blue]$a = array (10, 20, 30);[/color]
[color=blue]$a = array (’a’ => 10, ’b’ => 20, ’cee’ => 30);[/color]
[color=blue]$a = array (5 => 1, 3 => 2, 1 => 3,);[/color]
[color=blue]$a = array();[/color]
第二种方式是用数组操作器 ([ ]):
[color=blue]$x[] = 10;[/color]
[color=blue]$x[’aa’] = 11;[/color]
[color=blue]echo $x[0]; // 输出 10[/color]
第二种方式比第一种有更强的控制,它可以同时设定数组的值和键。
[b]打印数组[/b]
PHP有两个方法可以打印数组:print_r() 和 var_dump().
[list][*]两个方法都可以回归打印数组里的内容,但只有var_dump()可以显示每个值的数据类型。[*]只有var_dump()能够同时输出多个变量的值。[*]只有print_r()能以字符串形式返回输出。[/list]一般来讲,echo用的最多,而var_dump()和print_r()方法多用于查错。
[b]枚举型与关联型(Enumerative vs. Associative)[/b]
数组大概能粗分为两种:枚举型与关联型。枚举型数组的索引只能用数字,而关联型数组的索引可以用任何元素。但在PHP里,这种区分是很模糊的,因为用户可以建一个枚举型数组,然后加一个关联型数组进去。
当一个元素加入数组而没有指定健时,PHP将自动的在现有数组中最大的数字键中加1,作为新键指定给新元素。如:
[color=blue]$a = array (2 => 5);[/color]
[color=blue]$a[] = ’a’; // 其键值是 3[/color]
[color=blue]$a = array (’4’ => 5, ’a’ => ’b’);[/color]
[color=blue]$a[] = 44; // 其键值是 5[/color]
注意数组的键值是大小写敏感的,键‘A’跟键“a‘不一样,但”1“和 1 是一样的,但这只能用于十进制,因此,”01“和 1 是不一样的。
[b]多维数组[/b]
因为数组里的每一个元素都可以包含任何类型数据,所以创建多维数组非常容易:只有把一个数组指定为另一个数组的元素就行了。如:
[color=blue]$array = array();[/color]
[color=blue]$array[] = array([/color]
[color=blue] ’foo’, [/color][color=blue]
'bar’[/color]
[color=blue]);[/color]
[color=blue]$array[] = array([/color]
[color=blue] ’baz’, [/color]
[color=blue] 'bat’[/color]
[color=blue]);[/color]
[color=blue]echo $array[0][1] . $array[1][0];[/color]
输出结果是 barbaz 。
[b]提取数组 (Unravelling Arrays)[/b]
有时候可以通过指定数组元素的值到一个变量里,以便可以更方便的处理此值。PHP提供了list()方法,如:
[php]$sql = "SELECT user_first, user_last, lst_log FROM users";
$result = mysql_query($sql);
while (list($first, $last, $last_login) = mysql_fetch_row($result)) {
echo "$last, $first - Last Login: $last_login";
}[/php]
这样我们就可以在while循环里简单的使用这些元素了。
[b]数组操作[/b]
我们在PHP基础篇里提到,有些操作器在数组里的行为是很不一样的。如 + 操作器 :
[color=blue]$a = array (1, 2, 3);[/color]
[color=blue]$b = array (’a’ => 1, ’b’ => 2, ’c’ => 3);[/color]
[color=blue]var_dump ($a + $b);[/color]
结果 :
[color=blue]array(6) {[/color]
[color=blue] [0]=> [/color][color=blue]int(1)[/color]
[color=blue] [1]=> [/color][color=blue]int(2)[/color]
[color=blue] [2]=> [/color][color=blue]int(3)[/color]
[color=blue] ["a"]=> [/color][color=blue]int(1)[/color]
[color=blue] ["b"]=> [/color][color=blue]int(2)[/color]
[color=blue] ["c"]=> [/color][color=blue]int(3)[/color]
[color=blue]}[/color]
注意在结果数组里包括了原来两个数组的所有元素,即使它们有同样的值;这是因为它们的键不一样。如果连键值都一样,那结果就不同了:
[color=blue]$a = array (1, 2, 3);[/color]
[color=blue]$b = array (’a’ => 1, 2, 3);[/color]
[color=blue]var_dump ($a + $b);[/color]
结果 :
[color=blue]array(4) {[/color]
[color=blue] [0]=> [/color][color=blue]int(1)[/color]
[color=blue] [1]=> [/color][color=blue]int(2)[/color]
[color=blue] [2]=> [/color][color=blue]int(3)[/color]
[color=blue] ["a"]=> [/color][color=blue]int(1)[/color]
[color=blue]}[/color]
[b]数组比较[/b]
数组的比较相对的比较少发生,但我们可以用另外的操作器。如:
[color=blue]$a = array (1, 2, 3);[/color]
[color=blue]$b = array (1 => 2, 2 => 3, 0 => 1);[/color]
[color=blue]$c = array (’a’ => 1, ’b’ => 2, ’c’ => 3);[/color]
[color=blue]var_dump ($a == $b); // True[/color]
[color=blue]var_dump ($a === $b); // False[/color]
[color=blue]var_dump ($a == $c); // True[/color]
[color=blue]var_dump ($a === $c); // False[/color]
如例, 在数组有相同元素,相同值和键,无论次序,操作器 == 比较结果为真。而操作器 === 则只有在连次序都一样时,才为真。同样的,我们可以用不等于和非证实操作器来决定两个数组是否不一样:
[color=blue]$a = array (1, 2, 3);[/color]
[color=blue]$b = array (1 => 2, 2 => 3, 0 => 1);[/color]
[color=blue]var_dump ($a != $b); // False[/color]
[color=blue]var_dump ($a !== $b); // True[/color]
[b]统计,查找,和删除元素[/b]
数组的大小可以用 count()方法来查看:
[color=blue]$a = array (1, 2, 4);[/color]
[color=blue]$b = array();[/color]
[color=blue]$c = 10;[/color]
[color=blue]echo count ($a); // Outputs 3[/color]
[color=blue]echo count ($b); // Outputs 0[/color]
[color=blue]echo count ($c); // Outputs 1[/color]
如上例,count()方法不能判断一个变量是否是一个数组。但能用is_array()的方法。类似的问题是可以用isset()的方法来判断数组内的元素是否存在:
[color=blue]$a = array (’a’ => 1, ’b’ => 2);[/color]
[color=blue]echo isset ($a[’a’]); // True[/color]
[color=blue]echo isset ($a[’c’]); // False[/color]
但这种方法有一个缺点,那就是当元素存在,但选定键的值为NULL时,就不行了。如:
[color=blue]$a = array (’a’ => NULL, ’b’ => 2);[/color]
[color=blue]echo isset ($a[’a’]); // False[/color]
正确的方法是用array_key_exists()函数来代替:
[color=blue]$a = array (’a’ => NULL, ’b’ => 2);[/color]
[color=blue]echo array_key_exists ($a[’a’]); // True[/color]
但是,这些函数中没有一个可以用来判断是否有一个已知值的元素在数组里,这时就要用到in_array()函数了:
[color=blue]$a = array (’a’ => NULL, ’b’ => 2);[/color]
[color=blue]echo in_array ($a, 2); // True[/color]
最后,我们可以用unsetting()函数来删除数组中的一个元素。如:
[color=blue]$a = array (’a’ => NULL, ’b’ => 2);[/color]
[color=blue]unset ($a[’b’]);[/color]
[color=blue]echo in_array ($a, 2); // False[/color]
反转和倒转 (Flipping and Reversing)
有两个函数名字相当令人困惑,而且很容易误用:array_flip() 和 array_reverse()。第一个是用来反转数组中元素的键和值:
[color=blue]$a = array (’a’, 'b’, 'c’);[/color]
[color=blue]var_dump (array_flip ($a));[/color]
结果为:
[color=blue]array(3) {[/color]
[color=blue] ["a"]=> int(0)[/color]
[color=blue] ["b"]=> int(1)[/color]
[color=blue] ["c"]=> int(2)[/color]
[color=blue]}[/color]
第二个函数是用来倒转数组中元素的次序:
[color=blue]$a = array (’x’ => ’a’, 10 => ’b’, ’c’);[/color]
[color=blue]var_dump (array_reverse ($a));[/color]
注意,键值为数字的将失去其关联的健值。
[color=blue]array(3) {[/color]
[color=blue] [0]=> [/color][color=blue]string(1) "c"[/color]
[color=blue] [1]=> [/color][color=blue]string(1) "b"[/color]
[color=blue] ["x"]=> [/color][color=blue]string(1) "a"[/color]
[color=blue]}[/color]
[b]数组遍历[/b]
遍历是除数组创建外在数组中用得最多的方法。与其他语言不同,它们中的数组多为枚举型或连续型的。而PHP中需要一系列的函数来处理其可变性。看看这个数组:
[color=blue]$a = array (’a’ => 10, 10 => 20, ’c’ => 30);[/color]
很明显,到目前为止,我们讲到的函数中,没有一个可以用来循环数组内的元素。
[b]数组指针 (Array Pointer)[/b]
每个数组在遍历时都有一个指针制向当前的元素。指针有很多不同的结构,但只能由一系列的函数来操纵,并且不会影响对单个元素的操作,也不会影响其他“正常”的数组操作。这个指针事实上只是一个方便维护数组遍历状态,而不用外部变量来这种事情的工具。
这类操纵函数包括:reset(),prev() 和 next(),current(),和 key()。如:
[php]
$array = array(’foo’ => 'bar’, 'baz’, 'bat’ => 2);
function displayArray($array) {
reset($array);
while (key($array) !== null) {
echo key($array) .": " .current($array) . PHP_EOL;
next($array);
}
}
[/php]
这里我们创造了一个函数类显示数组里所有的元素。我们使用reset()来重置内部数组指针,使用key()和currect()来显示现在的键和值,使用next()来指向下一个元素。
[b]一个用于遍历的简易方式[/b]
PHP通过使用foreach()的结构提供了一个方便的捷径来遍历数组:
[color=blue]$array = array(’foo’, 'bar’, 'baz’);
[/color][color=blue]foreach ($array as $key => $value) {[/color]
[color=blue] echo "$key: $value";[/color]
[color=blue]}[/color]
[b]被动遍历[/b]
array_walk()函数和array_walk_recursive()函数能用于调用自定义函数来数组的遍历:
[php]
function setCase(&$value, &$key)
{
$value = strtoupper($value);
}
$type = array(’internal’, 'custom’);
$output_formats[] = array(’rss’, 'html’, 'xml’);
$output_formats[] = array(’csv’, 'json’);
$map = array_combine($type, $output_formats);
array_walk_recursive($map, ’setCase’);
var_dump($map);
[/php]
显示结果:
[color=blue]array(2) {[/color]
[color=blue]["internal"]=>[/color]
[color=blue] &array(3) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "RSS"[/color]
[color=blue] [1]=>[/color][color=blue]string(4) "HTML"[/color]
[color=blue] [2]=>[/color][color=blue]string(3) "XML"[/color]
[color=blue] }[/color]
[color=blue]["custom"]=>[/color]
[color=blue] &array(2) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "CSV"[/color]
[color=blue] [1]=>[/color][color=blue]string(4) "JSON"[/color]
[color=blue] }[/color]
[color=blue]}[/color]
[b]数组排序[/b]
PHP总共有11个用于排序的函数。就简单的是sort(), 如:
[color=blue]$array = array(’a’ => ’foo’, 'b’ => 'bar’, 'c’ => 'baz’);[/color]
[color=blue]sort($array);[/color]
[color=blue]var_dump($array);[/color]
结果:
[color=blue]array(3) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "bar"[/color]
[color=blue] [1]=>[/color][color=blue]string(3) "baz"[/color]
[color=blue] [2]=>[/color][color=blue]string(3) "foo"[/color]
[color=blue]}[/color]
这种方法摧毁了原来的键值。如果要保留原来的键值,可以用asort()函数:
[color=blue]$array = array(’a’ => 'foo’, 'b’ => 'bar’, 'c’ => 'baz’);[/color]
[color=blue]asort($array);[/color]
[color=blue]var_dump($array);[/color]
结果:
[color=blue]array(3) {[/color]
[color=blue] ["b"]=>[/color][color=blue]string(3) "bar"[/color]
[color=blue] ["c"]=>[/color][color=blue]string(3) "baz"[/color]
[color=blue] ["a"]=>[/color][color=blue]string(3) "foo"[/color]
[color=blue]}[/color]
sort()和asort()函数都可以接受第二个,可选的参数:
SORT_REGULAR -- 比较数组中的元素,不作任何转换。这是缺省方法。
SORT_NUMERIC -- 把每个元素转换成数值后排序。
SORT_STRING -- 把每个元素转换成字符串后排序。
sort()和asort()函数都是升序排序。如果要倒序排序,可用rsort()和arsort()。
有时使用sort()和asort()函数会产生一些不自然的顺序,比如字符串“10t”会被认为小于字符串“2t”,因为前者开始字符是1,而后者是2。这时可用natsort()函数,如:
[color=blue]$array = array(’10t’, '2t’, '3t’);[/color]
[color=blue]natsort($array);[/color]
[color=blue]var_dump($array);[/color]
结果:
[color=blue]array(3) {[/color]
[color=blue] [1]=>[/color][color=blue]string(2) "2t"[/color]
[color=blue] [2]=>[/color][color=blue]string(2) "3t"[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "10t"[/color]
[color=blue]}[/color]
[b]其他排序选择[/b]
使用ksort()和 krsort()函数来对数组元素的键(而不是数组元素的值)来排序, 如:
[color=blue]$a = array (’a’ => 30, ’b’ => 10, ’c’ => 22);[/color]
[color=blue]ksort($a);[/color]
[color=blue]var_dump ($a);[/color]
结果:
[color=blue]array(3) {[/color]
[color=blue] ["a"]=>[/color][color=blue]int(30)[/color]
[color=blue] ["b"]=>[/color][color=blue]int(10)[/color]
[color=blue] ["c"]=>[/color][color=blue]int(22)[/color]
[color=blue]}[/color]
最后,用户可以通过自定义函数来排序:
[php]
function myCmp ($left, $right)
{
// 通过值的长度排序。
// 如果长度一样,就作正常排序。
$diff = strlen ($left) - strlen ($right);
if (!$diff) {
return strcmp ($left, $right);
}
return $diff;
}
$a = array (
’three’,
’2two’,
’one’,
’two’
);
usort ($a, ’myCmp’);
var_dump ($a);
[/php]
结果:
[color=blue]array(4) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "one"[/color]
[color=blue] [1]=>[/color][color=blue]string(3) "two"[/color]
[color=blue] [2]=>[/color][color=blue]string(4) "2two"[/color]
[color=blue] [3]=>[/color][color=blue]string(5) "three"[/color]
[color=blue]}[/color]
反排序
有些情况下,用户需要数组元素的次序是随机的,而不是有序的,这时就需要用shuffle()函数,如:
[color=blue]$cards = array (1, 2, 3, 4);[/color]
[color=blue]shuffle ($cards);[/color]
[color=blue]var_dump ($cards);[/color]
结果:
[color=blue]array(9) {[/color]
[color=blue] [0]=>[/color][color=blue]int(4)[/color]
[color=blue] [1]=>[/color][color=blue]int(1)[/color]
[color=blue] [2]=>[/color][color=blue]int(2)[/color]
[color=blue] [3]=>[/color][color=blue]int(3)[/color]
[color=blue]}[/color]
以上例子中,键-值的关系没有了;但这可以用另一个函数array_keys()来很容易的进行补救。如:
[php]
cards = array (’a’ => 10, ’b’ => 12, ’c’ => 13);
$keys = array_keys ($cards);
shuffle($keys);
foreach ($keys as $v) {
echo $v . " - " . $cards[$v] . "\n";
}
[/php]
如果需要从数组中随机提取元素,可用array_rand()函数,它将从数组里返回一个或多个随机键值, 如:
[color=blue]$cards = array (’a’ => 10, ’b’ => 12, ’c’ => 13);[/color]
[color=blue]$keys = array_rand ($cards, 2);[/color]
[color=blue]var_dump ($keys);[/color]
[color=blue]var_dump ($cards);[/color]
结果:
[color=blue]array(2) {[/color]
[color=blue] [0]=>[/color][color=blue]string(1) "a"[/color]
[color=blue] [1]=>[/color][color=blue]string(1) "b"[/color]
[color=blue]}[/color]
[color=blue]array(3) {[/color]
[color=blue] ["a"]=>[/color][color=blue]int(10)[/color]
[color=blue] ["b"]=>[/color][color=blue]int(12)[/color]
[color=blue] ["c"]=>[/color][color=blue]int(13)[/color]
[color=blue]}[/color]
[b]数组作为栈,队列,和集[/b]
数组经常用作栈(后进,先出,或LIFO)和队列(先进,先出,或FIFO)结构。
先看如何用作栈(Stacks):
[color=blue]$stack = array();[/color]
[color=blue]array_push($stack, ’bar’, 'baz’);[/color]
[color=blue]var_dump($stack);[/color]
[color=blue]$last_in = array_pop($stack);[/color]
[color=blue]var_dump($last_in, $stack);[/color]
结果:
[color=blue]array(2) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "bar"[/color]
[color=blue] [1]=>[/color][color=blue]string(3) "baz"[/color]
[color=blue]}
[/color][color=blue]string(3) "baz"
[/color][color=blue]array(1) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "bar"[/color]
[color=blue]}[/color]
现在再看看如何用作队列(Queues):
[color=blue]$stack = array(’qux’, 'bar’, 'baz’);[/color]
[color=blue]$first_element = array_shift($stack);[/color]
[color=blue]var_dump($stack);[/color]
[color=blue]array_unshift($stack, ’foo’);[/color]
[color=blue]var_dump($stack);[/color]
结果:
[color=blue]array(2) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "bar"[/color]
[color=blue] [1]=>[/color][color=blue]string(3) "baz"[/color]
[color=blue]}[/color]
[color=blue]array(3) {[/color]
[color=blue] [0]=>[/color][color=blue]string(3) "foo"[/color]
[color=blue] [1]=>[/color][color=blue]string(3) "bar"[/color]
[color=blue] [2]=>[/color][color=blue]string(3) "baz"[/color]
[color=blue]}[/color]
[b]集的功能 (Set Functionality)[/b]
array_diff()函数能用于计算两个数组间的不同, 如:
[color=blue]$a = array (1, 2, 3);[/color]
[color=blue]$b = array (1, 3, 4);[/color]
[color=blue]var_dump (array_diff ($a, $b));
[/color]
此函数将保留所有$a中没有在$b里出现的值。结果是:
[color=blue]array(1) {[/color]
[color=blue] [1]=>[/color][color=blue]int(2)[/color]
[color=blue]}[/color]
这里,键又被忽略了。如果你要基於键-值配对来进行比较,那么可以用array_diff_assoc()函数。如果只比较键,那么可以用array_diff_key()函数。这两者都还有各自自定义的回叫函数(user supplied callbackfunction):array_diff_uassoc() 和 array_diff_ukey()。如:
[php]
function key_compare_func($a, $b)
{
if ($a === $b) {
return 0;
}
return ($a > $b)? 1:-1;
}
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
$array2 = array("a" => "green", "yellow", "red");
$result = array_diff_uassoc($array1, $array2, "key_compare_func");
print_r($result);
[/php]
[color=#000000][/color]
[color=#000000]结果:[/color]
[color=blue]Array[/color]
[color=blue]([/color]
[color=blue] => brown[/color]
[color=blue] [c] => blue[/color]
[color=blue] [0] => red[/color]
[color=blue])[/color]
与array_diff()函数不同, array_intersect()函数用于计算两个数组间的交集:
[color=blue]$a = array (1, 2, 3);[/color]
[color=blue]$b = array (1, 3, 4);[/color]
[color=blue]var_dump (array_intersect ($a, $b));[/color]
结果将显示两个数组间共有的元素:
[color=blue]array(2) {[/color]
[color=blue] [0]=>[/color][color=blue]int(1)[/color]
[color=blue] [2]=>[/color][color=blue]int(3)[/color]
[color=blue]}[/color]
PHP也提供了array_intersect_key() 和array_intersect_assoc()函数来处理键-值配对的问题,还同样有回叫变量array_intersect_ukey() 和array_intersect_uassoc()函数。
[b]小结[/b]
数组也许是PHP里最有力的数据管理工具。因此,学会正确使用这些函数是成为一个优秀开放人员的基础。
当然,不要为了考试而成为一个“活手册”,但是,要清楚的理解什么时候使用内置函数,什么时候要自己写解决方法。因为数组经常用来处理大量数据,所以PHP内置函数总会比自定义函数更优化,快捷。
页:
[1]
