1.リスト
複数のスカラ変数を並べた構造を『リスト』といいます。リストはスカラと同じように数値、文字列を区別なく扱います。リストの書き方はとても簡単で、値をカンマで区切り、その全体をカッコで囲むだけです。1、2、3の 3 つの値のリストは、以下のように表します。
(1, 2, 3)
リストの代入
リストの要素に代入する場合は、下記のような方法があります。
($a, $b, $c) = (1, 2, 3);
リストの中にリストがある場合には、自動的に展開されます。
(@list1, @list2, &function)
上記のようなリストは @list1 のすべての要素の後に @list2 のすべての要素を追加し、その後にfunction というサブルーティンが返すすべての要素を追加します。
リストの要素数と変数の数が違う場合
リストの要素数よりも、用意した変数のほうが多い場合には、あまった値は捨てられます。
($a, $b, $c) = (1, 2, 3, 4, 5);
上記の場合、リストの最初の3つの要素1、2、3がそれぞれ$a、$b、$cに代入され、残りの要素4、5は捨てられます。
逆に、リストの要素数よりも変数のほうが少ない場合、あまった変数には未定義値が代入されます。
($a, $b, $c) = (1, 2);
$aには1、$bには2、$cには未定義値の undef が代入されます。
リストと配列
一般的にリストが使われるのは、『配列』に対して値を設定するときです。リストのうち、変数名をつけたものを配列と呼びます。配列を宣言するときは変数名の前にアットマーク( @ )を付けるのが決まりになっています。
@list = (1, 2, 3);
上記の例では、配列 @list は、1、2、3という3つの値を持つようになります。
2.配列へ値を代入
スカラ変数の場合は1つの変数に対して1つの値を代入するだけでしたが、配列の場合は複数の値を代入することができるため、スカラ変数とは違う代入の書式があります。
配列の初期化
空の配列の作成は次のようにします。値の入った配列を初期化するのにも使えます。
@week = ( );
配列の宣言と同時に値を代入するには、要素全体をカッコで囲み、各要素をカンマで区切ります。
@week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
インデックスを指定して要素に値を代入
配列はスカラ変数の要素ごとに『インデックス』を持っています。インデックスは個々の要素にアクセスするときに使います。たとえば$week[0]は、配列の1番目の要素を表します。インデックスの使用の際に注意するのは、2点です。まず、配列の最初の要素のインデックスは0 になります。1番目の要素のインデックスは 0 、2番目の要素は 1 になります。次に、配列の要素はスカラ変数ですから、変数名の前につくマークはアットマーク( @ )ではなくダラー( $ )になります。
$week[0] = 'Sun'; $week[1] = 'Mon';
qw演算子を使って初期化することもできます。qw 演算子はスペース( )で区切った単語を配列として返します。
@week = qw(Sun Mon Tue Wed Thu Fri Sat);
要素の範囲を指定して値を代入することもできます。
# 0 から 3 までの要素に値を代入 $week[0..3] = ('Sun','Mon','Tue','Wed');
値を捨てる
localtime関数のように沢山の値が帰ってくる場合、必要な値だけを変数に渡す方法がいくつかあります。
# こんなにいらないし、メモリの無駄使い ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime( $time ); # スライスでほしい値を選択するが一番スマートな方法 ($mday, $mon, $year) = (localtime( $time ))[3,4,5]; # undef で値を捨てるのもあり (undef undef, undef, $mday, $mon, $year, undef, undef, undef) = localtime( $time );
3.配列の値を参照
配列への値代入と同様に、値を参照する場合も配列独自の書式があります。
インデックスを使って配列の値を参照
配列の要素を参照するには、$week[2]のように、インデックスを[ ] で囲んで指定します。
@week = (Sun, Mon, Tue, Wed, Thu, Fri, Sat); # 配列 @week の3番目の要素を表示 print "$week[2]\n"; > Tue
配列のインデックスは0から始まるので、$week[2] は3つめの要素「Thu」を参照します。
配列を展開する
配列の要素をすべて表示する場合は下記のとおりです。
# 全ての配列の要素を表示 print "@week"; > Sun Mon Tue Wed Thu Fri Sat
上記の例では、配列をダブルクォーテーション( " )で囲み、変数展開をしています。スカラ変数の場合は単一の値が表示されるわけですが、配列の場合はすべての値がスペース()で区切られて表示されます。
配列を出力するときの区切り文字は特殊変数 $" で変更できます。
$" = ','; print "@week"; > Sun,Mon,Tue,Wed,Thu,Fri,Sat
配列をダブルクォーテーション( " )で囲まない場合は、展開が行われないので、配列の各要素の値は区切りもいなしで表示されます。
# 全ての配列の要素を表示 print @week; > SunMonTueWedThuFriSat
配列の要素数を調べる
配列の要素数は配列をスカラに代入することで得られます。
$length = @week; # $length の値は 7
配列の要素数を調べ、要素がなければエラーにする場合は以下のようにします。
if ( $#list < 0 ){ die("配列が空です!"); }
最後のインデックスの数値を調べる
「$#配列名」という表記は、配列の最後のインデックスの数値を表します。配列のインデックスは0から始まるので、配列の要素よりも1つ小さい値になります。
# 配列の最後にあたるインデックスを表示 print "$#week\n"; > 6
「$#配列名」 に代入することにより、配列の要素数を小さくしたり、空にしてしまうこともできます。
# 配列の初期化 @list = (1,2,3); #配列の最後のインデックスを3にする $#list = 2;
4.配列の使い方
for 文を使って配列にアクセス
配列のすべての要素にアクセスするには for文や foreach文が便利です。
@list = (One, Tow, Three); for( $i=0 ; $i <= $#list ; $i++ ){ print $list[$i], "\n"; }
foreach 文を使って配列にアクセス
foreachを使って書き直したものが次の例です
@list = (One, Tow, Three); foreach my $value ( @list ){ print $value, "\n"; }
配列の超絶テクニック大全集
文字列から配列をつくる
配列を作る簡単な作り方は split を使ってデータをそのまま配列にする方法です。
$values = 'One,Two,Three'; @array = split( /,/, $values ); print $array[0]; > One print "@array"; > One Two Three
配列から特定の要素を確かめる
配列の要素が文字列である場合の最も速いやり方は、配列の値をキーとしたハッシュを用意する方法です。
@array = qw/rhythm factory express biztech/; %tmp; for ( @array ) { $tmp{$_} = 1 }
こうすれば、$tmp{$some_value}があるかをチェックすることで、配列の要素を確かめることができます。
配列の値のすべてが小さな整数であれば、単純な添え字付き配列を使うことができます。
@array = (1, 2, 4, 8, 16, 32); @tmp; for ( @array ) { $tmp[$_] = 1; }
こうすれば、$tmp[$some_value]があるかをチェックすることで、配列の要素を確かめることができます。
配列から重複した要素を抜き取る
配列からユニークな要素だけを取り出す方法は、決まった順序で取り出したいのか、配列に格納されている順序がどうであるのかによります。
ソートされている配列からユニークな要素だけを取り出す
#! /usr/local/bin/perl @array = (1,2,3,3,4); $x = '-'; @sort = grep( $_ ne $x && ($x = $_), @array );
print @sort, "\n";
> 1234
ソートされていない配列からユニークな要素だけを取り出す
@array = (1,3,3,2,4); %tmp; @sort = grep( !$tmp{$_}++, @array ); print @sort, "\n"; > 1324
ソートされていない配列からユニークな要素だけを取り出す(配列が小さな整数のみ)
@sort = grep( !$tmp[$_]++, @array );
配列をスタックやキューとして使う
Perlには、配列の先頭や末尾に対して要素を追加、削除するためのshift、unshift、push、pop という4つの関数があります。
- | 要素を追加 | 要素を取り除く |
---|---|---|
先頭に | unshift | shift |
末尾に | push | pop |
unshift
for ($i=5; $i<10; $i++) { unshift(@a, $i); # @a の最初に $i を追加 } print "@a"; > 9 8 7 6 5
push
for ($i=0; $i<5; $i++) { push(@a, $i); # @a の最後に $i を追加 } print "@a"; > 0 1 2 3 4
unshift、pushは要素を加えていくときに使います。unshiftは最初に加え、pushは最後に加えます。
pop
@a = (9,8,7,6,5); for ($i=0; $i<5; $i++) { print pop(@a); } > 56789
shift
@a = (9,8,7,6,5); for ($i=0; $i<5; $i++) { print shift(@a); } > 98765
pop、shiftは取り出すときに使います。popはうしろから、shiftは先頭から取り出します。
ファイルを逆順に表示
スタックとキューを使ってファイルを逆順に表示するプログラムを作ります。
# 順に配列に入れる while(<>){ push(@buf,$_); } while(@buf){ # @buf は配列の長さを返す print pop(@buf); # 後ろから取り出す }
2つの配列の差、もしくは共通する要素数を調べる
2つの配列の差、もしくは共通要素を求めるには、ハッシュを使います。ただし、与えられた配列の要素には重複がないと仮定しています。
@array1 = (1,2,4,8,16,32); @array2 = (1,2,4,8,16,64); @intersection; @difference; %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (keys %count) { push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element; } print "差:", $#difference + 1,"\n"; > 差: 2 print "共通:", $#intersection + 1,"\n"; > 共通: 5
配列から条件にマッチする要素を見つける
最初に見つけた要素のインデックス保存する方法が一般的です。
@array = qw(Sun Mon Tue Wed Thu Fri Sat); for ( $i=0; $i < @array; $i++ ) { if ( $array[$i] eq "Mon" ) { # "Mon"という値であれば $index = $i; # インデックスを保存して last; # for ループを終了 } } print $array[$index], "\n"; > Mon
配列からランダムに要素を選択する
配列からランダムに要素を選択するには、rand()関数を使います。
srand; # rand() 用のシード値を用意(5.004以降では不要) @array = 1 .. 100; # 配列の用意 $index = rand @array; print $array[$index], "\n"; > 38
配列の要素の順番をランダムする
カレントの要素をランダムに取り出した別の要素と交換します
srand; # rand() 用のシード値を用意 @array = 1 .. 10; # 配列の用意 @new; while ( @array ) { push( @new, splice(@array , rand @array , 1) ); } print @new, "\n"; > 82173910546
大きな配列に対しては、以下の方法がよいでしょう。
srand; # rand() 用のシード値を用意(5.004以降では不要) @array = 1 .. 100; # 配列の用意 @new; for( @array ){ my $r = rand @new+1; push(@new, $new[$r]); $new[$r] = $_; } print "@new\n";
多次元配列を静的に作成
多次元配列とは、配列を要素とした配列のことです。次のような2次元配列はよく使われる例です。
@list = ( [ "LUCY", "LIU" ], [ "CAMERON", "DIAZ" ], [ "DREW", "BARRYMORE", "produced by drew" ], ); print $list[0][0], " & ", $list[1][0], " & ", $list[2][0]; > LUCY & CAMERON & DREW print $list[2][2]; > produced by drew
多次元配列にアクセス
# 要素に値を代入 $list[0][0] = "Jini"; # リファレンスを使って全体を表示 for my $ref( @list ){ print "@$ref\n"; } # 1つずつ全体を表示(シンプルな方法) for my $ref( @list ){ for $ref2( @{$ref} ){ print $ref2, "\n"; } } # 1つずつ全体を表示 for my $i( 0 .. $#list ){ for $j ( 0...$#{$list[$i]} ){ print "$i $j : $list[$i][$j]\n";
} }