Perl入門ゼミ

テキスト処理、Linuxサーバー管理、Web開発ならPerl
  1. Perl
  2. here

Perlの配列を理解しよう

配列は複数の値を保存することのできる変数です。同じ種類のデータを複数扱う必要がある場合に配列を使用します。Perlの配列は動的配列と呼ばれるものでサイズを自動的に拡張してくれるので便利です。

配列の基礎

配列の基礎について解説します。

  • 配列の宣言
  • 初期化
  • 要素の参照
  • 要素への代入
  • 配列の個数
  • 繰り返し処理

配列の宣言

配列を宣言するにはスカラ変数の場合と同じようにmyを使用します。配列を表す@(アットマーク)を先頭につけます。

my @numbers;

配列の初期化

配列にはリストと呼ばれる複数の値を表現するデータを代入することができます。リストは

(値1, 値2, 値3)

のように()を使って表現します。

配列にリストを代入するには次のようにします。

@numbers = (10, 25, 40, 4, -6);

配列の宣言と代入を同時に行うこともできます。

my @numbers = (10, 25, 40, 4, -6);

配列の要素の参照

配列の要素を参照するには次のようにします。先頭の文字が@ではなくて$であることに注意しましょう。添え字は0から始まります。

$配列[添え字]

次のようにして、先頭の要素と2番目の要素を出力できます。

print $numbers[0];
print $numbers[1];

配列の要素の代入

代入を行うには次のようにします。

$配列[添え字] = 値

先頭の要素に20を代入してみます。

$numbers[0] = 20;

配列の要素の個数

配列の個数を取得するには配列をスカラコンテキストで評価します。スカラコンテキストについての解説は別のところで行いますが、最初のうちは配列をスカラ変数に代入すると配列の個数が取得できると覚えておきましょう。

my $cnt = @nums;

配列の要素数の取得する方法の詳しい解説は以下の記事をご覧ください。

配列の要素を順番に処理する

配列の要素を順番に処理するにはfor文かforeach文を使用します。forは添え字を使用して順番にアクセスしたい場合に利用し、foreachは単純に配列を順番に処理したい場合に使用します。foreachで処理できない場合にforを使用するようにするのがPerlでの良い習慣です。

for文で配列の要素を順番に出力してみます。

for (my $i = 0; $i < @nums; $i++) {
  print $nums[$i], "\n";
}

foreach文で配列の要素を順番に出力してみます。

foreach my $num (@nums) {
  print $num, "\n";
}

配列の要素の操作

関数を使用して配列に要素を追加したり、取り出したりすることができます。

  • shift関数
  • unshift関数
  • pop関数
  • push関数

shift関数

「shift関数」を使えば、配列の「先頭の要素を取得」することができます。@arrayが(1, 2, 3)であった場合は$firstには1が代入され、@arrayは(2, 3)になります。

my $first = shift @array;

unshift関数

「unshift関数」を使えば、配列の「先頭に要素を追加」することができます。@arrayが(1, 2, 3)であった場合は@arrayは(5, 1, 2, 3)になります。

unshift @array, 5;

pop関数

「pop関数」を使えば、配列の「末尾の要素を取り出す」ことができます。@arrayが(1, 2, 3)であった場合は$lastには3が代入され@arrayは(1, 2)になります。

my $last = pop @array;

push関数

「push関数」を使えば、配列の「末尾に要素を追加」することができます。。@arrayが(1, 2, 3)であった場合は@arrayは(1, 2, 3, 5)になります。

push @array, 5;

配列の並べ替え

配列を並べ替えるにはsort関数を使用します。

sort関数

第1引数には比較のためのコードブロックを渡します。昇順で並べ替える場合は$aを$bより先に記述し、降順で並べ替えるには$bを$aより先に記述します。比較演算子には数値として比較したい場合は<=>を使用し、辞書順で比較したい場合はcmpを使用します。

# 昇順で並べ替え
@sorted = sort { $a 演算子 $b } @array;

# 降順で並べ替え
@sorted = sort { $b 演算子 $a } @array;

数値の昇順で並べ替えるてみます。@numsは(2, 3, 5, 8)になります。

# 数値の昇順で並び替え
my @nums = (5, 8, 3, 2);
@nums = sort {$a <=> $b} @nums;

簡単に逆順に並び替える

簡単に逆順に並び替えたい場合は「reverse関数」を使うこともできます。

@reverse = reverse @elements;

配列のリファレンス

リファレンスとは、配列の入っているメモリの位置を指すもの。C言語を知っているなら、「アドレス演算ができないポインタ」だと考える。Javaを知っているなら、「参照」だと考える。

配列のリファレンスの作成

my $numbers_ref1 =  \@numbers ;

@の前に、\をつけると、配列のリファレンスを作成できる。

直接配列のリファレンスを作成する

my $numbers_ref2 = [1, 2, 3, 4];

リストを [ ] でくくると、配列のリファレンスになる。

配列の要素の参照

$numbers_ref2->[0]

配列のリファレンス->[ 要素番号 ]

配列と配列のリファレンスの比較

配列と配列のリファレンスの比較をしてみました。見間違いやすので、ふたつの違いをよく理解できるようになりましょう。

要素の参照

# 配列
$numbers[0]

#配列のリファレンス
$numbers_ref->[0]

配列のリファレンスのデリファレンス

@$numbers_ref

for文や、配列を引数にとる関数など配列に戻したいときはデリファレンスする

配列のリファレンスについては以下のページでも詳しく解説しています。

リスト

リストとは複数の値の並びを表現したものです。リストと配列とは異なります。リストは表記方法なのに対して、配列は変数です。

# リスト
('a',    case  :

  break;b', 'c', 'd')

リストは配列に代入することができます。

# 配列への代入
my @array = ('a', 'b', 'c', 'd');

リストについての詳細は「リスト - 複数の値の並び」をご覧ください。

配列に関する関数・構文・演算子

splice関数

配列の要素に対して複雑な操作を行うにはsplice関数を使用します。複数の要素を取り出したり、置換したりすることができます。複数要素の取り出しにおいて$lengthを省略すると$posの位置から配列の末尾までが対象になります。

# 複数要素の取り出し
@parts = splice @array, $pos, $length;

# 複数要素の置換
splice @array, $pos, $length, @replace;

grep関数

grep関数」を使用すると配列の中で条件にマッチした要素のみを取り出すことができます。デフォルト引数$_に@arrayの各要素が渡されてきます。条件文を満たした要素のみが@matchedに追加されます。

# 条件にマッチした要素のみを取り出す
@matched = grep { 条件文 } @array;

map関数

配列のすべての要素を変換するにはmap関数を使用します。@arrayの各要素がデフォルト変数$_に渡されてきますので、コードブロック{ }の中で必要な変換を行います。変換文で最後に評価されたものが@mappedに順番に追加されます。

# 配列のすべての要素の変換
@mapped = map { 変換文 } @array;

文字列リスト演算子

文字列のリストを簡潔に記述するための文字列リスト演算子と呼ばれる演算子があります。文字列リスト演算子を使用するとシングルクォートやカンマを記述することなく文字列のリストを表現できます。

qw(文字列1 文字列2 文字列3)

実際に文字列リスト演算子を使用した例です。

my @strings = qw/cat dog mouse/; 

次の文字列のリストと同じ意味になります。

my @strings = ('cat', 'dog', 'mouse');

配列スライス

配列から要素番号を指定して複数の要素を取り出すには配列スライスと呼ばれるテクニックを使います。

# 配列スライス
my @values = @array['m', 'n', ...]

配列とハッシュを組み合わせた「多次元データ構造」

「配列」と「ハッシュ」と「リファレンス」を組み合わせた「多次元データ構造」を理解することは、中級者になるためには、必要不可欠です。

# ハッシュの配列
my $persons = [
  {name => 'Kimoto', age => 36},
  {name => 'Tanaka', age => 20}
]

「多次元データ構造」については次の記事で詳しく解説していますので、参考にしてください。

サンプルプログラム

配列の要素の検索、配列の重複した要素を取り除く、重複を数える

配列の要素の検索、配列の重複した要素を取り除く、重複を数えるサンプルです。

use strict;
use warnings;

my @numbers = (1, 2, 3, 3, 4, 5, 6, 6, 6, 7, 8);
print '配列 : @numbers = (' . join(',', @numbers) . ")\n\n";

# 1:配列に指定した要素が含まれているかどうかを調べる。
# grepを応用します。
my $saerch_number = 3;
if (grep { $_ == $saerch_number } @numbers) {
  # 検索する要素が、見つかったら、if文の中は真になります。
  print "1: $saerch_numberは存在します。\n";
}

# 2:配列から重複を取り除く( 順序は保障されない )
#ハッシュのキーは重複を許さないという性質を持つ。
my %no_duplicate_hash;
for my $number (@numbers) {
  $no_duplicate_hash{$number}++;
}

# ハッシュのキーのリストを取得
my @no_duplicate_numbers = keys %no_duplicate_hash; 
print '2: @no_duplicate_numbers = (' . join(',', @no_duplicate_numbers) . ")\n\n";

# 3:配列に含まれる重なる要素の個数を数える(上の続き)
print "3: 要素の個数\n";
for my $key (sort keys %no_duplicate_hash) {
  print "$keyは$no_duplicate_hash{$key}個含まれます。\n";
}

配列のリファレンス

配列のリファレンス、配列への変換、要素の参照についてのサンプルプログラムです。

use strict;
use warnings;

my @numbers = (1, 2, 3, 4, 5, 6, 7, 8);
print "配列 : \@numbers = ( " , join(',', @numbers) . " )\n\n";

# 1:配列のリファレンス @の前に \ をつけると、配列のリファレンスになる。
my $numbers_ref1 =  \@numbers ;

# 配列のリファレンスの前に@をつけると元の配列に戻すことができる。
# これを、デリファレンスという。
print "配列 : \@\$numbers_ref1 = (" . join(',', @$numbers_ref1),")\n";

# 2: けれど、普通は上のような書き方はしない。
# 無名配列( [ ] )というものを使って、直接配列のリファレンスを作る。
my $numbers_ref2 = [1, 2, 3, 4]; 
print "配列 : \$numbers_ref2 = [" , join(',', @$numbers_ref2) . "]\n\n";

#3: 配列の要素にアクセスする。( $array_ref->[ 要素番号 ] )
print "\$numbers_ref2->[0] = $numbers_ref2->[0]\n";
print "\$numbers_ref2->[1] = $numbers_ref2->[1]\n";

実行結果

配列 : @numbers = (1,2,3,4,5,6,7,8)

配列 : @$numbers_ref1 = (1,2,3,4,5,6,7,8)
配列 : $numbers_ref2 = [1,2,3,4]

$numbers_ref2->[0] = 1
$numbers_ref2->[1] = 2

配列と配列のリファレンスの比較のサンプル

配列と配列のリファレンスがどう違うかが見ることができるサンプルプログラムです。

use strict;
use warnings;

my @numbers = (1, 2, 3);
print "配列 : \@numbers = (" , join(',', @numbers), ")\n\n";

my $numbers_ref = [1, 2, 3];

# 1. 要素の参照
print "1. 要素の参照\n";
print "\$numbers[0] = ", $numbers[0], "\n";

# 配列のリファレンス
print "\$numbers_ref->[0] = ", $numbers_ref->[0], "\n";
print "\n";

# 2. 各要素の処理
print "2. 各要素の処理\n";

# 配列
print "\@numbers = "  ;
for my $number (@numbers) {
  print $number . "," ;
}
print "\n";

# 配列のリファレンス( for文に、デリファレンスしてわたす)
print "\@{ \$numbers_ref } = ";
for my $number (@$numbers_ref){
  print $number . ","
}
print "\n\n";

# 3. 関数の使い方
print "3. 関数の使い方\n";

# 配列
push @numbers, 4;
@numbers = sort { $b <=> $a } @numbers;
print "\@numbers = (" , join(',', @numbers),")\n";

# 配列のリファレンス(デリファレンスして関数に渡す)
push @$numbers_ref, 4;

# sort関数は、配列を返すので、無名配列[ ]を使って
# 配列のリファレンスを再作成している。
$numbers_ref = [sort { $b <=> $a } @$numbers_ref]; 
print "\@\$numbers_ref = (" , join(',', @$numbers_ref),")\n\n";

実行結果

配列 : @numbers = (1,2,3)

1. 要素の参照
$numbers[0] = 1
$numbers_ref->[0] = 1

2. 各要素の処理
@numbers = 1,2,3,
@{ $numbers_ref } = 1,2,3,

3. 関数の使い方
@numbers = (4,3,2,1)
@$numbers_ref = (4,3,2,1)

コラム「動的配列を言語機能に組み入れたPerl」

Perlに言語機能として組み込まれている配列は、自由に値を追加したり、削除したりできるので、動的配列と呼ばれます。

Perlは言語機能として、動的配列を言語に組み入れる素晴らしい決定をした。配列を自由に扱えるとても便利なアイデアだ。これは大成功で、後発のほとんどのスクリプト言語は動的配列を言語に組み入れている。

言語学者ラリーウォールが作成したアイデアの宝庫としてのPerlは今でも生きている。

Giblog