位元詩人 [Perl] 程式設計教學:陣列 (Array) 和串列 (List)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

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 的第一、第二、第三個值。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。