Perl學習筆記03——列表和陣列
列表和陣列
▲
1.列表指的是標量的有序集合,而陣列則是儲存列表的變數。更精確地說,列表指的是資料,而陣列指的是變數。
2.陣列或列表中的每個元素都有相應的整數作為索引,從0開始遞增,每次加1。
3.陣列或列表每個元素都是獨立不相關的標量值,所以列表或陣列可能包含數字、字串、undef值或是不同型別標量值的混合。
4.列表的值不一定要放在數組裡,但每個陣列變數都一定包含一個列表(即便是不含任何元素的空列表)。
訪問陣列中的元素
▲
訪問陣列元素:
print $fred[0];
修改陣列元素:
$fred[2] = "diddly";
▲
任何求值能得到數字的表示式都可以用作下標,假如它不是整數,則會自動捨去小數,無論正負。
$number = 2.71828; print $fred[$number - 1]; #結果和print $fred[1]相同
▲
假如下標超出陣列的末端,則對應的值將會是undef。
特殊的陣列索引($#rocks)
▲
如果對索引值超過陣列尾端的元素進行賦值,陣列將會根據需求自動擴大,增補元素預設取值為undef。
$rocks[0] = 'bedrock'; #一個元素 $rocks[1] = 'slate'; #又一個元素 $rocks[99] = 'schist'; #現在有97個undef元素
▲最後一個元素的索引值
對陣列rocks而言,最後一個元素的索引值是
$end = $#rocks; #99,也就是最後一個元素的索引值 $number_of_rocks = $end + 1; #100,陣列元素的個數 print $rocks[$#rocks]; #訪問最後一個元素
▲負數陣列索引
注意:超出陣列大小的負數索引值只會得到undef,而不會繞回到陣列尾部。
print $rocks[-1]; #和$rocks[$#rocks]一樣,但更簡單 print $rocks[-100]; #得到'bedrock' $rocks[-200] = 'crystal'; #致命錯誤!
列表直接量
▲
列表直接量(也就是在程式程式碼中表示一列資料的寫法),可以由小括號內用逗號隔開的一串資料表示,這些資料就稱為列表元素。
(1,2,3) #包含數字1、2、3這三個數字的列表 (1,2,3,) #包含數字1、2、3(末尾的逗號會被忽略) ("fred",4.5) #兩個元素,"fred"和4.5 () #空列表——零個元素
▲範圍操作符(..)
如果是某種規律的序列,不用逐個鍵入。範圍操作符(..)可用於自動建立它兩側標量值之間的所有值。
(1..100) #從1到100的整數序列 (1..5) #等同於(1,2,3,4,5) (1.7..5.7) #同上,等同於(1,2,3,4,5),小數點部分去掉後取範圍 (0,2..6,10,12) #等同於(0,2,3,4,5,6,10,12)
NOTE:
1.範圍操作符只能從小到大依次累加
(5..1) #得到的是空列表
2.列表中的元素可以不必都是常數,它們可以是表示式。
($m,17) ($m+$o, $p+$q) ($m..$n) (0..$#rocks) #rocks陣列的下標序列
▲qw簡寫
qw簡寫可以快速輸入,免除反覆鍵入引號和逗號。
("fred","barney","betty","wilma","dino") 等同於 qw( fred barney betty wilma dino)
NOTE:
1.在qw構建的列表中,Perl都會將其當成單引號內的字串來處理,所以,不能像雙引號內的字串一樣使用\n或$fred。其中的空白字元(如空格、製表符以及換行符)會被拋棄,然後剩下的就是列表中的元素。
所以,上面列表可以寫成這樣:
qw( fred
barney betty
wilma dino)
2.因為qw算是一種引用的形式,所以不能將註釋放在qw列表中。
qw( fred #abc,在這裡加註釋會被當成一個元素 barney betty wilma dino )
3.除了圓括號(),Perl還允許用任何標點符號作為定界符,也可以是成對符號。
qw!fred barney betty wilma dino! qw/fred barney betty wilma dino/ qw#fred barney betty wilma dino# qw{fred barney betty wilma dino} qw[fred barney betty wilma dino] qw<fred barney betty wilma dino>
注意:
(1)如果需要在被圈引的字串內使用定界符,可通過反斜線轉義來引入這個字元。
qw! yahoo\! google ask msn ! #將yahoo!作為一個元素引入
(2)和單引號內的字串一樣,兩個連續的反斜線表示一個實際的反斜線。
qw( This is a \\ real backslash);
列表的賦值
▲列表值賦值到變數
($fred, $barney, $dino) = ("flintstone", "rubble", undef);
NOTE:
1.如果變數個數>列表值的個數,多出來的值會被忽略掉
($fred, $barney) = qw< flintstone rubble slate granite > #忽略掉末尾的兩個元素
2.如果變數個數<列表值的個數,多出來的變數會被設成undef(或空列表,後面解釋)
($wilma, $dino) = qw[flinstone]; #$dino的值為undef
▲交換兩個變數的值
($fred, $barney) = ($barney, $fred); ($betty[0], $betty[1]) = ($betty[1], $betty[0]);
▲構建一個字串陣列
($rock[0], $rock[1], $rock[2], $rock[3]) = qw/talc mica feldspar quartz/;
▲引用整個陣列(用@字元)
在賦值操作符兩邊都可以用
@rock = qw/bedrock slate lava/; @tiny = (); #空列表 @giant = 1..1e5; #包含100000個元素的列表 @stuff = (@giant, undef, @giant); #包含200001個元素的列表
注意:
1.
$dino = "granite"; @quarry = (@rock, "crushed rock", @tiny, $dino);
這個賦值運算將會把@quarry的值設成擁有5個元素的列表(bedrock, slate, lava, crushed rock, granite),因為@tiny貢獻了0個元素給這個列表(注意,由於空列表裡沒有任何元素,也就不會有undef被賦值到列表中,如果需要undef,也可以顯式寫明)。
2.
列表中的陣列名會被展開成(它所擁有的)元素列表,因為陣列只能包含標量,不能包含其他陣列,所以陣列無法成為列表中的元素。
3.
就像標量變數的初始值是undef一樣,新的或是空的陣列的初始值是空列表,即()。
pop和push操作符
▲pop操作符:提取陣列末尾的元素並將其作為返回值
@array = 5..9; $fred = pop(@array); # $fred為9,@array現在是(5,6,7,8) $barney = pop @array; # $barney為8,@array現在是(5,6,7) pop @array; # @array現在是(5,6),pop的返回值7被拋棄了
NOTE:
1.最後一行是在“空上下文”中使用pop操作符。所謂空上下文,只不過是表示返回值無處可去的一種說辭。這其實也是pop操作符常見的一種用法,用來刪除陣列中最後一個元素。
2.如果陣列是空的,pop什麼也不做,直接返回undef。
3.pop後面加不加括號都可以。
▲push操作符:新增一個(或一串)元素到陣列尾端
@array = (5,6); push (@array, 0); # @array現在是(5,6,0) push @array, 8; # @array現在是(5,6,0,8) push @array, 1..10 # @array得到了10個新元素 @others = qw/5 2 0 y f b/; push @array, @others; # @array又得到了6個新元素(共20個)
注意:
push或pop的第一個引數都必須是要操作的陣列變數,對列表直接量進行壓入(push)或彈出(pop)操作是沒有意義的。(因為對列表直接量進行操作後,處理後的列表又怎麼表示呢?)
shift和unshift操作符
▲shift操作符:提取陣列開頭的元素並將其作為返回值
@array = qw#dino fred barney#; $m = shift(@array); # $m變成"dino",@array現在是("fred", "barney") $n = shift @arry; # $n變成"fred",@array現在是("barney") shift @array; # 現在@array變空了 $o = shift @arry; # $o變成undef,@array還是空的
▲unshift操作符:新增一個(或一串)元素到陣列開頭
unshift(@array, 5); # @array現在僅包含只有一個元素的列表(5) unshift @array, 4; # @array現在是(4,5) @others = 1..3; unshift @array, @others; # @array變成了(1,2,3,4,5)
splice操作符
push-pop和shift-unshift操作符都是針對陣列首尾的元素操作的,splice操作符是針對陣列中間的元素操作的。
splice含義:刪除操作。
▲splice可接受4個引數,後兩個引數可選
splice(引數1,引數2,引數3,引數4)
引數1:要操作的陣列
引數2:要操作的一組元素的開始位置(索引值)
引數3(可選):指定要操作的元素長度(即元素個數)
引數4(可選):要替換的列表
▲接受兩個引數:
@array = qw(pebbles dino fred barney betty); @removed = splice @array, 2; #在原來的陣列中刪掉從fred(索引值為2)開始往後的元素 #@removed變成qw(fred barney betty) #原先的@array變成qw(pebbles dino)
NOTE:
1.splice返回值是什麼? ——刪除的元素列表
2.是"原地更新"嗎? ——是
▲接受三個引數
第3個引數作用是指定要操作的元素長度(注意不是結束位置),即元素個數,通過這個引數,可以刪除陣列中間的一個片段。
@array = qw(pebbles dino fred barney betty); @remoed = splice @array, 1, 2; #刪除dino和fred兩個元素 # @remoed變成qw(dino fred) # @array變成qw(pebbles barney betty)
▲接受四個引數
第4個引數是要替換的列表,也就是可以補充新元素到原來的陣列中,新加入列表的長度不一定要和拿走的元素片段長度一樣。
@array = qw(pebbles dino fred barney betty); @remoed = splice @array, 1, 2, qw(wilma); #刪除dino和fred # @remoed變成qw(dino fred) # @array變成qw(pebbles wilma barney betty)
▲特殊用法
實際上,新增元素列表並不需要預先刪除某些元素,把表示長度的第三個引數設為0,既可不加刪除地插入新列表。
@array = qw(pebbles dino fred barney betty); @remoed = splice @array 1, 0, qw(wilma); #什麼元素都不刪除 # @remoed變成() # @array變成qw(pebbles wilma dino fred barney betty)
注意:
wilma出現在dino 之前的位置上,Perl從索引值1的地方插入新列表,然後順移原來的元素。
字串中的陣列內插
▲
和標量一樣,陣列的內容同樣可以被內插到雙引號引起的字串中。內插時,會在陣列的各個元素之間自動新增分隔用的空格。
@rocks = qw( flinstone slate rubble); print "quartz @rocks limestone\n"; #列印5個以空格隔開的單詞
NOTE:
1.陣列被內插後,首尾都不會增添額外空格,若真的需要,可以自己手動新增
2.如果@為雙引號內字串的內容本身時,需引入反斜線轉義\@或直接用單引號來定義字串
$email = "[email protected]"; #錯!這樣會內插@bedrock這個陣列 $email = "fred\@bedrock.edu"; #正確 $email = '[email protected]'; #另一種寫法,效果相同
3.內插陣列中的某個元素時,會被替換成該元素的值。
@fred = qw(hello dolly); $y = 2; $x = "This is $fred[1]'s place"; #得到This is dolly's place $x = "This is $fred[$y-1]'s place"; #效果同上
4.如果要在某個標量變數後面緊接著寫左方括號,需要隔離,否則會被識別為陣列引用。
@fred = qw(eating rocks is wrong); $fred = 'right'; print "this is $fred[3]\n"; #用到了$fred[3],列印"wrong" print "this is ${fred}[3]\n"; #列印right[3](用花括號避開歧義) print "this is ${fred}"."[3]\n"; #列印right[3](用分開的字串) print "this is $fred\[3]\n"; #列印right[3](用反斜線避開歧義)
foreach控制結構
▲foreach迴圈能逐項遍歷列表中的值,依次提取使用:
foreach $rock(qw/ bedrock slate lava /){ print "One rock is $rock.\n"; #依次列印這三個單詞 }
NOTE:
1.每次迴圈迭代時,控制變數$rock都會從列表中取得新值。
2.控制變數並不是列表元素的複製品,實際上,它就是列表元素本身。也就是說,假如在迴圈體中修改了控制變數的值,也就同時修改了列表元素。
@rocks = qw/ bedrock slate lava /; foreach $rock(@rocks){ $rock = "\t$rock"; #在@rocks的每個元素前加上製表符 $rock .= "\n"; #同時在末尾加上換行符 } print "The rocks are:\n",@rocks; #各自佔一行,並使用縮排(注意這種寫法,從第二個列表元素開始前面都帶一個空格)
注意:
@rocks = qw(a b c d); print @rocks; #會得到abcd print "@rocks"; #會得到a b c d
▲
迴圈結束後,控制變數的值仍然是迴圈執行之前的值。Perl會自動儲存foreach迴圈的控制變數並在迴圈結束後還原。
在迴圈執行期間,我們無法訪問或改變已儲存的值,所以當迴圈結束時,變數仍讓保持迴圈前的值。
如果它之前從未被賦值,那就仍然是undef。
也就是說,如果想把迴圈的控制變數取名為$rock的話,不必擔心之前是否用過同名的變數。
$rock = 'shale'; @rocks = qw/ bedrock slate lava /; foreach $rock(@rocks){ ... } print "rock is still $rock\n"; #列印'rock is still shale'
Perl的預設變數:$_
▲
假如在foreach迴圈開頭省略控制變數,Perl就會用它最喜歡用的預設變數$_。
這個變數名除了名稱比較特別以外,和其它標量變數幾乎沒什麼差別。
foreach (1..10){ #預設會用$_作為控制變數 print "I can count to $_!\n"; }
▲
Perl有許多預設變數,$_是最常用的一個,如果不加說明,Perl預設使用$_。
$_ = "Yabba dabba doo\n"; print; #預設列印$_
reverse操作符
▲
reverse操作符會讀取列表的值(一般來自陣列),並按相反次序返回新的列表。
@fred = 6..10; @barney = reverse(@fred); #返回10,9,8,7,6 @wilma = reverse 6..10; #同上,但無需額外的陣列 @fred = reverse @fred; #倒序後儲存到原來的陣列
注意:
reverse只是返回倒序後的列表,它不會修改給它的引數。加入返回值無處可去,那這種操作也就變得毫無意義。
reverse @fred; #錯誤的用法,這不會使陣列內容倒序 @fred = reverse @fred; #正確用法
sort操作符
▲
sort操作符會讀取列表的值(一般來自陣列),依次按字元的內部編碼順序對它們排序。
排序按照ASCII碼的大小進行。
@rocks = qw/ bedrock slate rubble granite /; @sorted = sort(@rocks); #返回bedrock,granite,rubble,slate @back = reverse sort @rocks; #逆序,從 slate 到 bedrock 排列 @rocks = sort @rocks; #將排序後的結果存到原陣列@rocks @numbers = sort 97..102; #得到100,101,102,97,98,99
NOTE:
1.按預設排序規則,任何以1開頭的字串會被排在以9開頭的字串之前。
2.排序操作和reverse操作一樣,不會修改原始引數,只是返回新的列表。所以要對陣列排序,就必須將排序後的結果存回陣列。
each操作符
從Perl 5.12開始,已經可以針對陣列使用each操作符了。在這之前each只能用於提取雜湊的鍵-值對。
▲
每次對陣列呼叫each,會返回陣列中下一個元素對應的兩個值——陣列索引與元素值:
require v5.12; @rocks = qw/ bedrock slate rubble granite /; while (($index, $value) = each @rocks){ print "$index: $value\n"; }
注意:
這裡使用了require,因為使用use v5.12會預設啟用“嚴格(strict)”模式。
▲
如果不用each,就得根據索引從小到大遍歷,然後藉助索引取得元素值。
@rocks = qw/ bedrock slate rubble granite /; foreach $index(0..$#rocks){ print "$index: $rocks[$index]\n"; }