配列

次のプログラムはキーボードから5つの整数を読み込んで平均値を計算します。

program work0601
  implicit none
  integer :: n1, n2, n3, n4, n5

  write(*,*) 'Input N1:'
  read(*,*) n1
  write(*,*) 'Input N2:'
  read(*,*) n2
  write(*,*) 'Input N3:'
  read(*,*) n3
  write(*,*) 'Input N4:'
  read(*,*) n4
  write(*,*) 'Input N5:'
  read(*,*) n5

  write(*,*) 'Mean = ', (n1 + n2 + n3 + n4 + n5) / 5.0d+0

  stop
end program work0601

読み込む数字が5ではなく100だったらどうなるでしょう. 数字を記憶しておくために100個の変数を用意するは大変です.

このような場合に役に立つのが「配列 (array)」です. 配列は同じ型の変数の集まりを「添字(そえじ)」と呼ばれる番号で管理します. 配列は次のように宣言します.

integer :: nx(5)

この宣言によって nx は integer 型の変数が5個集まった配列となります. 配列の各要素は,配列の名前に続けて ( ) の中に番号を入れて, nx(1), nx(2), nx(3), nx(4), nx(5) と表します. この番号のことを「添字」といいます. 添字は通常,先頭から順に 1, 2, 3, … となります。

5つの要素を持つ配列 nx
┌─┬─┬─┬─┬─┐
│1│2│3│4│5│
└─┴─┴─┴─┴─┘

配列は同一の型を持つ変数の集合です. 配列 nx のどの要素も integer 型の変数であることに注意しましょう.

配列と do 文

5つの要素をもつ integer 型の配列を用意し,先頭から順に 1, 2, 3, 4, 5 を代入して,平均値を表示するプログラムを以下に示します.

program work0602
  implicit none
  integer :: nx(5)              ! 配列の宣言

  nx(1) = 1
  nx(2) = 2
  nx(3) = 3
  nx(4) = 4
  nx(5) = 5

  write(*,*) (nx(1) + nx(2) + nx(3) + nx(4) + nx(5)) / 5.0d+0

  stop
end program work0602

このプログラムを do 文を使って書き換えると次のようになります.

program work0603
  implicit none
  integer :: nx(5), i

  do i = 1, 5
     nx(i) = i
  end do

  write(*,*) (nx(1) + nx(2) + nx(3) + nx(4) + nx(5)) / 5.0d+0

  stop
end program work0603

練習問題

5つの要素をもつ integer 型の配列を用意し,先頭から順に 11, 12, 13, 14, 15 を代入して,平均値を表示するプログラムを作成せよ. do 文を利用すること.

配列の初期化

変数を宣言する際は,明らかに必要のない場合(do 変数など)を除いて初期化すべきです. 変数と同様に,配列も宣言時に初期化することができます. 次の例では,配列の各要素を順に 1, 2, 3, 4, 5 で初期化しています.

program work0605
  implicit none
  integer :: nx(5) = (/ 1, 2, 3, 4, 5 /)    ! 配列の初期化
  integer :: i

  do i = 1, 5
     write(*,*) nx(i)
  end do

  stop
end program work0605

(/ 1, 2, 3, 4, 5 /) のことを「配列生成子」といいます.

また,配列のすべての要素を,あるひとつの値で初期化する場合は,代入文を使って

integer :: nx(5) = 0            ! すべての要素を 0 にする

と書くことができます.

練習問題

5つの要素をもつ integer 型の配列を用意し,先頭から順に 3, 1, 4, 1, 5 で初期化して, 値を表示するプログラムを作成せよ. do 文を利用すること.

配列に値を読み込む

配列の各要素にキーボードから値を読み込み,それを表示するプログラムを示します. 値を読み込むために read 文を利用するのは通常の変数の場合とまったく同様です.

program work0607
  implicit none
  integer :: nx(5), i

  do i = 1, 5
     write(*,*) 'Input nx(', i, ')'
     read(*,*) nx(i)
  end do

  do i = 1, 5
     write(*,*) i, nx(i)
  end do

  stop
end program work0607

次のようにして,配列に一度に値を読み込むことができます.

program work0608
  implicit none
  integer :: nx(5), i

  write(*,*) 'Input nx(1:5)'
  read(*,*) nx(1:5)

  do i = 1, 5
     write(*,*) i, nx(i)
  end do

  stop
end program work0608

read(*,*) nx(1:5) は次と同じ意味になります.

read(*,*) nx(1), nx(2), nx(3), nx(4), nx(5)

キーボードから値を入力するときは,5つの数字を空白で区切って1行にまとめましょう.

% ./a.out
 Input nx(1:5)
1 2 3 4 5

配列を逆順に並び替える

配列の値を先頭から順に読み込み,それを逆順に並び替えることを考えてみましょう. nx(1) から nx(5) までの5つの要素を並び替えるには

nx(1) と nx(5) を交換
nx(2) と nx(4) を交換

という作業が必要です. これをプログラムにすると次のようになります.

program work0609
  implicit none
  integer :: nx(5), i, tmp

  write(*,*) 'Input nx(1:5)'
  read(*,*) nx(1:5)

  ! 逆順に並び替える
  do i = 1, 2
     tmp = nx(i)
     nx(i) = nx(6-i)
     nx(6-i) = tmp
  end do

  do i = 1, 5
     write(*,*) i, nx(i)
  end do

  stop
end program work0609

2つの変数の値を交換するのに

x = y
y = x

としてはいけません(x も y も,もとの y の値になってしまいます). ひとつ余分な変数(上の例では tmp)を用意して

tmp = x                         ! x の値を tmp に保存
x = y                           ! x に y の値を代入
y = tmp                         ! y に保存しておいた x の値を代入

とする必要があります.

練習問題

work0609 を書き換えて,配列の要素数を 8 に変更せよ.

配列のコピー

ある配列を別の配列にコピーするには2つの方法があります.

do 文を利用して要素ごとにコピーする方法

program work0611
  implicit none
  integer :: nx(5) = (/ 1, 2, 3, 4, 5 /), ny(5) = 0

  do i = 1, 5
     ny(i) = nx(i)
  end do

  do i = 1, 5
     write(*,*) ny(i)
  end do

  stop
end program work0611

代入文を利用してコピーする方法

program work0612
  implicit none
  integer :: nx(5) = (/ 1, 2, 3, 4, 5 /), ny(5) = 0

  ny(1:5) = nx(1:5)             ! 配列のコピー

  do i = 1, 5
     write(*,*) ny(i)
  end do

  stop
end program work0612

代入文を利用する場合,2つの配列の要素数が等しいときは,添字の範囲を省略することができます.

ny = nx

ただし,この書き方では nx, ny が配列なのか,あるいは通常の変数なのか, この部分をみただけでは区別できません. そこで,nx, ny が配列であることが一目でわかるように,

ny(1:5) = nx(1:5)

と書くほうがよいという意見もあります.

練習問題

work0612 を書き換えて,配列 nx の要素の並びを逆順に ny にコピーするプログラムを作成せよ.

最大値を見つける

次の例は,キーボードから5つの整数を入力し,その最大値を求めるプログラムです.

program work0614
  implicit none
  integer :: nx(5), i, tmp

  write(*,*) 'Input 5 integers:'
  read(*,*) nx(1:5)

  ! 最大値を見つける
  tmp = nx(1)
  do i = 2, 5
     if (nx(i) > tmp) tmp = nx(i)
  end do

  write(*,*) tmp

  stop
end program work0614

最大値をみつけるために,仮の最大値として tmpnx(1) の値を代入しておきます. do ループを使って nx(2), nx(3), ..., nx(5) との大小比較を行い, tmp より大きい値が見つかったら tmp = nx(i) によって tmp の値を更新します.

練習問題

work0614 を書き換えて,最小値を見つけるプログラムを作成せよ.

本日の課題

最小値・最大値を見つける

キーボードから5つの整数を入力し,最小値と最大値を同時に求めるプログラムを作成せよ.

クリックして表示

平均値を求める

キーボードから5つの整数を入力し,その平均値を求めるプログラムを作成せよ.

クリックして表示

ベクトルの内積

2つの3次元ベクトル x, y をキーボードから読み込み,内積 x.y を計算するプログラムを作成せよ。 x, y は real(8) 型の配列とする. 3次元ベクトルは要素数 3 の配列で表すことができる.

クリックして表示