前言
Perl 的陣列 (array) 是一種線性的容器,以數字做為索引,可儲存異質資料。串列則是一序列的資料。這兩者有一些關連,本文介紹 Perl 陣列和串列。
陣列 (Array) 和串列 (List) 的差異
在 Perl 裡面,陣列和串列不完全相同,如 push 函式的宣告:
push ARRAY, LIST
push
會把串列加入陣列尾端,由此可知,Perl 對陣列和串列的看法有差異。
我們看一下以下的程式碼片段:
my @arr = ("foo", "bar", "baz");
在這個程式碼中,@arr
是陣列,而 ("foo", "bar", "baz")
是串列。由此可知,陣列是儲存串列的變數,串列是一個序列的資料。
建立陣列
以下程式碼片段用空串列建立空陣列:
my $arr = ();
以下程式碼片段用現有的串列建立陣列:
my @arr = ("foo", "bar", "baz");
以下程式碼片段用現有的陣列建立新陣列:
my @a = (1, 2, 3);
my @b = (10, @a, 11);
這時候 @a
會自動攤平 (flatten),@b
會是 (10, 1, 2, 3, 11)
。
以索引 (index) 存取陣列
存取陣列元素時,以數字為索引 (index),從零開始計數 (zero-based)。如下例:
my @arr = ("foo", "bar", "baz");
$arr[0] == "foo" or die "Wrong value";
$arr[1] == "bar" or die "Wrong value";
$arr[2] == "baz" or die "Wrong value";
要注意,我們一開始宣告 @arr
時,其 sigil 是 @
,但我們以 $arr[0]
取索引時,其 sigil 是 $
。Perl 針對不同類型的變數會使用不同的 sigil,一開始容易寫錯,需注意。
取得陣列長度
使用 scalar 函式可取得陣列長度,如下例:
my @a = (1, 2, 3);
my @b = (10, @a, 11);
scalar(@a) == 3 or die "Wrong length";
scalar(@b) == 5 or die "Wrong length";
Perl 另外有一個 length
函式,該函式用來取得字串長度,而非陣列長度。
scalar
其實牽涉到語境 (context) 的概念,我們留在後文介紹。
取得陣列尾端的索引
使用 $#
搭配陣列變數可取得尾端的索引值。參考下例:
my @arr = (1, 2, 3, 4, 5);
$#arr == 4 or die "Wrong index";
修改 $#
sigil 所指向的變數會改變陣列的長度,故不建議這麼做。
走訪陣列
使用 for
迴圈搭配計數器可走訪陣列:
my @arr = ("foo", "bar", "baz", "qux");
for (my $i = 0; $i < scalar(@arr); $i++) {
print $arr[$i], "\n";
}
如果不需計數器,也可以直接走訪串列:
my @arr = ("foo", "bar", "baz", "qux");
for my $e (@arr) {
print $e, "\n";
}
在此處,for
可使用陣列或串列來走訪,皆視為串列。
清空陣列
對陣列指派空串列可清空原有的陣列,如下例:
@arr = ();
操作陣列的函式
Perl 內建一些操作陣列的函式,可用來搬移資料。
push
push 會將額外的元素加入陣列尾端,如下例:
my @arr = ("foo", "bar");
push @arr, "baz", "qux", "quux";
scalar(@arr) == 5 or die "Wrong length";
$arr[2] == "baz" or die "Wrong value";
$arr[4] == "quux" or die "Wrong value";
pop
pop 會從陣列尾端移除一個元素,如下例:
my @arr = ("foo", "bar", "baz");
my $popped = pop @arr;
$popped == "baz" or die "Wrong value";
scalar(@arr) == 2 or die "Wrong length";
unshift
unshift 會將元素放入陣列頭端,如下例:
my @arr = ("foo", "bar");
unshift @arr, "baz", "qux", "quux";
scalar(@arr) == 5 or die "Wrong length";
$arr[0] == "baz" or die "Wrong value";
$arr[1] == "qux" or die "Wrong value";
$arr[2] == "quux" or die "Wrong value";
shift
shift 會從陣列頭端移除一個元素,如下例:
my @arr = ("foo", "bar", "baz");
my $shifted = shift @arr;
$shifted == "foo" or die "Wrong value";
scalar(@arr) == 2 or die "Wrong length";
splice
splice 會在陣列中任一位置插入元素,其宣告如下:
splice ARRAY,OFFSET,LENGTH,LIST
splice ARRAY,OFFSET,LENGTH
splice ARRAY,OFFSET
splice ARRAY
由此宣告可知,splice
有四個使用情境:
splice ARRAY,OFFSET,LENGTH,LIST
:在OFFSET
處,移除長度為LENGTH
的元素後,插入LIST
splice ARRAY,OFFSET,LENGTH
:在OFFSET
處,移除長度為LENGTH
的元素splice ARRAY,OFFSET
:移除OFFSET
後所有的元素splice ARRAY
:移除所有元素
以下是實例:
my @arr = ("foo", "bar", "baz", "qux");
my $shifted = splice @arr, 1, 2, "quux";
scalar(@arr) == 3 or die "Wrong length";
$arr[1] == "quux" or die "Wrong value";
陣列和串列的解構運算
我們可以將串列指派到另一個串列:
my ($a, $b, $c) = (1, 2, 3);
$a == 1 or die "Wrong value";
$b == 2 or die "Wrong value";
$c == 3 or die "Wrong value";
若右方串列過長,多餘的值會自動拋棄:
my ($a, $b, $c) = (1, 2, 3, 4, 5);
若左方串列過長,多餘的變數會變成未定義:
my ($a, $b, $c) = (1, 2);
!defined($c) or die "Wrong value";
也可以將串列指派到陣列:
my ($a, $b, @arr) = (1, 2, 3, 4, 5);
scalar(@arr) == 3 or die "Wrong length";
$arr[0] == 3 or die "Wrong value";
$arr[1] == 4 or die "Wrong value";
$arr[2] == 5 or die "Wrong value";
這時候 @arr
會接收右方剩餘的串列元素,故為 (3, 4, 5)
。
還可以將陣列拆開:
my ($a, $b, $c) = @arr;
這時候 $a
、 $b
、$c
分別會指派為 @arr
的第一、第二、第三個值。