前面我講過(guò)簡(jiǎn)單的數(shù)組遍歷,這些基于foreach,for之類(lèi)的語(yǔ)句,下面我來(lái)介紹數(shù)組的高級(jí)遍歷方法介紹,各位朋友可參考,這些數(shù)組才真用于開(kāi)發(fā)實(shí)用性能強(qiáng),復(fù)雜也更高了.
PHP對(duì)數(shù)組的處理可以稱(chēng)為該語(yǔ)言最有吸引力的特性之一,它支持70多種數(shù)組相關(guān)的函數(shù),不論你想翻轉(zhuǎn)一個(gè)數(shù)組、判斷某個(gè)值在數(shù)組中是否存在、將數(shù)組轉(zhuǎn)換成一個(gè)字符串還是計(jì)算數(shù)組的大小,僅僅執(zhí)行一個(gè)現(xiàn)有的函數(shù)就可以完成。然而也有一些數(shù)組相關(guān)的任務(wù)對(duì)開(kāi)發(fā)者的要求就較高,僅僅知道手冊(cè)有某個(gè)功能是不能解決的,這些任務(wù)就需要對(duì)PHP的原始特性有一些深入的理解,還需要一些解決問(wèn)題的想象力。
多維關(guān)聯(lián)數(shù)組排序
PHP提供了一些數(shù)組排序的函數(shù),比如sort(), ksort(),和asort(),但是卻沒(méi)有提供對(duì)多維關(guān)聯(lián)數(shù)組的排序。
比如這樣的數(shù)組:
要將該數(shù)組按照升序排序,你需要自己寫(xiě)一個(gè)函數(shù)用于比較價(jià)格,然后將該函數(shù)作為回調(diào)函數(shù)傳遞給usort()函數(shù)來(lái)實(shí)現(xiàn)該功能,代碼如下:
執(zhí)行了該程序片段,數(shù)組就會(huì)被排序,結(jié)果如下所示:
要將該數(shù)組按照降序排序,把comparePrice()函數(shù)里面的兩個(gè)減的數(shù)調(diào)換位置就可以了.
逆序遍歷數(shù)組
PHP的While循環(huán)和For循環(huán)是遍歷一個(gè)數(shù)組最常用的方法,但是你怎樣遍歷像下面這個(gè)數(shù)組呢?
PHP標(biāo)準(zhǔn)庫(kù)中有一個(gè)對(duì)集合的迭代器iterators類(lèi),它不僅僅能夠用于遍歷一些異構(gòu)的數(shù)據(jù)結(jié)構(gòu)(比如文件系統(tǒng)和數(shù)據(jù)庫(kù)查詢(xún)結(jié)果集),也可以對(duì)一些不知道大小的嵌套數(shù)組的遍歷,比如對(duì)上面的數(shù)組的遍歷,可以使用RecursiveArrayIterator迭代器進(jìn)行,代碼如下:
執(zhí)行該段代碼會(huì)給出以下的結(jié)果:
name: Board
name: chess
price: 12.99
name: checkers
price: 9.99
過(guò)濾關(guān)聯(lián)數(shù)組的結(jié)果
假定你得到了如下一個(gè)數(shù)組,但是你僅僅想操作價(jià)格低于$11.99的元素:
使用array_reduce()函數(shù)可以很簡(jiǎn)單的實(shí)現(xiàn),代碼如下:
array_reduce()函數(shù)會(huì)過(guò)濾掉不滿足回調(diào)函數(shù)的所有的元素,本例子的回調(diào)函數(shù)就是filterGames,任何價(jià)格低于11.99的元素會(huì)被留下,其他的會(huì)被剔除,該代碼段的執(zhí)行結(jié)果:
對(duì)象轉(zhuǎn)換成數(shù)組
一個(gè)需求就是將對(duì)象轉(zhuǎn)換成數(shù)組形式,方法比你想象的簡(jiǎn)單很多,僅僅強(qiáng)制轉(zhuǎn)換就可以了,實(shí)例代碼如下:
執(zhí)行該例子就會(huì)產(chǎn)生如下結(jié)果:
將對(duì)象轉(zhuǎn)換成數(shù)組會(huì)出現(xiàn)一些不可預(yù)料的副作用,比如上面的代碼段,所有的成員變量都是public類(lèi)型的,但是對(duì)于private私有變量的返回結(jié)果會(huì)變得不一樣,下面是另外一個(gè)例子,代碼如下:
正如你所看到的,為了進(jìn)行區(qū)分,數(shù)組中保存的私有變量的key被自動(dòng)改變了。
數(shù)組的“自然排序”
PHP對(duì)于“字母數(shù)字”字符串的排序結(jié)果是不確定的,舉個(gè)例子,假定你有很多圖片名稱(chēng)存放于數(shù)組中,代碼如下:
你怎樣對(duì)這個(gè)數(shù)組進(jìn)行排序呢?如果你用sort()對(duì)該數(shù)組排序,結(jié)果是這樣的:
有時(shí)候這就是我們想要的,但是我們想保留原來(lái)的下標(biāo)怎么辦?解決該問(wèn)題可以使用natsort()函數(shù),該函數(shù)用一種自然的方法對(duì)數(shù)組排序,代碼如下:
運(yùn)行結(jié)果:
遍歷過(guò)程中的改值操作
引用操作符&
看下面這段代碼中的$array數(shù)組,在foreach循環(huán)時(shí)對(duì)$value使用引用操作符,這樣在循環(huán)中修改$value的值的時(shí)候,便將$array中對(duì)應(yīng)的元素值修改了,代碼如下:
上段代碼的輸出如下:
Array ( [A] => 2 [B] => 2 [C] => 2 [D] => 2 )
可以看到,$array中各個(gè)鍵對(duì)應(yīng)的值都被修改成了2。看來(lái)這種方法確實(shí)奏效。
利用鍵值操作數(shù)組的元素
有的時(shí)候,數(shù)組中表示的可能是一些互相關(guān)聯(lián)的元素,如果遇到了這些相互關(guān)聯(lián)的元素中的一個(gè),就將其他元素做一個(gè)標(biāo)記的話,上面的引用肯定就不管用了,這時(shí)候修改這些關(guān)聯(lián)元素的時(shí)候,就要使用其對(duì)應(yīng)的鍵值了,先試試看管用不,代碼如下:
別著急看輸出,我們想象中的應(yīng)該是什么樣呢?打印修改后的數(shù)組,打印一個(gè)“CHANGE”,再打印一遍修改后的數(shù)組,對(duì)嗎?來(lái)看一下輸出吧!
Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE )
Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE )
咦?怎么個(gè)情況?我們的CHANGE哪去了?
按照我們的想法,既然$array已經(jīng)改變了,那么當(dāng)遍歷到鍵值為“D”的元素時(shí),應(yīng)當(dāng)輸出它的新值“CHANGE”才對(duì)!可是事實(shí)并不是我們想的那樣,PHP在這里做了什么手腳呢?把上面的代碼稍微修改一下,既然打印數(shù)組的時(shí)候,“D”=>CHANGE沒(méi)錯(cuò),那我們修改第二個(gè)if語(yǔ)句的判斷條件,代碼如下:
猜猜它會(huì)輸出什么?$value肯定不會(huì)等于“CHANGE”啦!難道等于1么?代碼如下:
Array ( [A] => CHANGE [B] => 1 [C] => 1 [D] => CHANGE )
那么,它確實(shí)就是1了。
這究竟是神馬原因呢?翻到PHP文檔的foreach那頁(yè),恍然:
Note: 除非數(shù)組是被引用,foreach 所操作的是指定數(shù)組的一個(gè)拷貝,而不是該數(shù)組本身,foreach對(duì)數(shù)組指針有些副作用,除非對(duì)其重置,在 foreach 循環(huán)中或循環(huán)后都不要依賴(lài)數(shù)組指針的值。
原來(lái)foreach所操作的是指定數(shù)組的一個(gè)拷貝,怪不得,取$value不管用了呢!理解到這里,上面的問(wèn)題就解決了,只要在foreach中,直接按照鍵取$array中的元素進(jìn)行各種判斷賦值操作就可以了。
總結(jié)及延伸:PHP的數(shù)組遍歷和操作能力確實(shí)非常強(qiáng)大,然而對(duì)一些稍復(fù)雜問(wèn)題的解決方法卻不是那么明顯,其實(shí)在任何領(lǐng)域都是這樣,一個(gè)語(yǔ)言和語(yǔ)法提供的都是基本的操作,對(duì)于復(fù)雜的問(wèn)題的解決辦法都需要開(kāi)發(fā)者自己的思考、想象力和代碼編寫(xiě)來(lái)完成。