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";
}
}