1. 程式人生 > >PHP強化之03 - 陣列 Array

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); 

//執行結果:
[email protected]:~$ 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