Programmierkurs
für Naturwissenschaftler/innen

配列

配列は言語によって扱い方が大きく異なるので、他の言語を学ぶ際には注意を要する。

配列とは (まずは概要)

詳しい説明は後にするとして、まずは配列がどんなものかについてざっくりと見てみよう。

実験データーがあってそれの処理 (計算) をしたいとする。 そのデーターが例えば 100 個あったとして、プログラムを書く際に、

data1 = 0.10
data2 = 1.2
data3 = 3.2
  :
  :
data100 = 1.1

と書いたとしよう。 もしこの和を求めようと思ったら、

summation = data1 + data2 + (省略) + data100

と書かなくてはならない。大変面倒である。 もし、追加のデーターが得られたとしたら、さらに、

data101 = 0.92
data102 = 5.8
data103 = 7.2
  :
  :

と追加した上で、 summation を求める部分も変更しなくてはならない。 これはただの和なのでまだ楽であるが、より複雑な計算 (例えば分散の計算) であればもっと面倒になるであろう。 手で計算した方がよっぽど早いということにもなりかねない。

そこで、配列の登場である。

data = [0.10, 1.2, 3.2, ...]

のように書く。 このとき各データーは data[0], data[1], … として使うことができる。

上の和を求めるプログラムは、

summation = data[0] + data[1] + (省略) + data[99]

と書き直すこともできるが、もっと簡単に、

summation = 0
for i in range(len(data)):
    summation += data[i]

と書くことができる (len() についてはこの後で述べる)。

データーが増えたとしても、 data = ... の部分だけ変更すれば良く、和を求める部分は一切変更しなくてよい。 プログラムも短くなり、従って見通しも良くなる。

このように、複数のデーター (値) をまとめたものが配列である。

なお、この形式は Python では リスト と呼ばれるのであるが、この文書では「配列」で統一する。

また、上のプログラムは Python ではもう少しスマートな書きかたができる。 それについては後述する。

配列の使い方

では配列について詳しく見ていくことにしよう。

定義

配列を定義するには上の例にもあるように、

data = [10, 20, 30]

などのように書く。 左辺はいままでの変数の定義と同じである。 右辺が配列特有の書きかたである。 かぎ括弧の中にデーターをコンマで区切って書く。 それぞれのデーター (ここでは 10 とか 20 とか) のことを配列の「要素」という。

Python では、配列の内容を print() で表示することができる。

次のプログラムを入力し、実行してみよ。

data = [10, 20, 30]
print(data)

実行結果

配列の要素を使う

配列の個々の要素を扱うには、 data[1] のように 変数名 + [ + 数字 + ] とする。 この数字を「添字」(そえじ) という。 Python の 配列の添字は 0 から始まる 。 従って最初の要素を表示するには、 print(data[0]) とする。

次のプログラムを入力し、実行してみよ。

data = [10, 20, 30]
print(data[0])
print(data[1])
print(data[2])

実行結果

配列の要素数 (長さ) を知るには

配列の要素数のことをしばしば「長さ」という。 配列の長さは、 len(配列名) で取得できる。 例えば、

data = [1, 2, 5]
print(len(data))

を実行すると 3 が表示される。

少しややこしいが、 len(配列) は配列の 要素の個数 である。 一方、配列の 最後の添字len(配列) - 1 であることに注意されたい。

ある配列の総和を計算したい場合は、

data = [1.2, 3, 5, 1.1]
summation = 0

for i in range(len(data)):
    summation += data[i]

と書ける。

プログラム中にデーターの個数を直接書いてはいけない:

for i in range(4):    # ! 悪い書きかた !
    summation += data[i]

これは文法的には間違っていないが、データーの要素数が直接プログラム内に書かれており (このような書き方をハードコーディングという)、バグの温床になる。 データーが増えたとき、最小限の変更で済むように、この場合はデーター のみ を変更すれば良いようにしておくべきである。

配列の長さが必要な場合は、必ず len() を使って書こう

次のプログラムを入力し、実行してみよ。

data = [10, 20, 30]
print(data)
print(len(data))

for i in range(len(data)):
    print("data[", i, "] =", data[i])

実行結果

次のプログラムを入力し、実行してみよ。

data = [10, 20, 30]
print(data)
print(len(data))

summation = 0
for i in range(len(data)):
    summation += data[i]
print(summation)

実行結果

  1. 次のプログラムを入力し、実行してみよ。

    # ! 良くない書き方 !
    
    data = [10, 20, 30]
    print(data)
    print(len(data))
    
    summation = 0
    for i in range(3):
        summation += data[i]
    print(summation)
  2. 3 行目の data に追加のデーターを書け。 例えば、

    data = [10, 20, 30, 40]

    そして、全ての要素の合計が計算されるように (つまり、40 を追加した場合は最終結果として 100 が得られるように) プログラムを変更せよ。

  3. なぜこの書き方が良くないか、検討せよ。

実行結果

配列と for

これまでは、配列の要素は常に添字によって指定してきた。 これは配列と添字の関係に慣れてもらいたかったからである。

しかし、Python ではもう少しすっきりした書きかたができる。

data = [10, 20, 30]
print(data)
print(len(data))

summation = 0
for elem in data:
    summation += elem
print(summation)

このように書くと for 文は data の要素を elem に入れてループを順次実行する。

さきほどの例と比較してみると、

for i in range(len(data)):
    summation += data[i]

が、

for elem in data:
    summation += elem

となっている。 変数 (i) が減っており、記述量も減っている。

こちらがより Python 的な書きかたである。

なお、添字ではなく要素であるということを明確にするために、 for での変数を (i ではなく) elem と書いた。 文法的には i のままでも問題ないが、 通常 i は (0,) 1, 2, 3, … のような「数える」ための整数値 (ループカウンターと呼ぶことがある) に使われるので、ここでは避けるべきである。

以下の二つのプログラムをそれぞれ実行してみよ。 一つ目と二つ目のプログラムのどこがどのように対応しているか確認せよ。

data = [10, 20, 30]

for i in range(len(data)):
    print(data[i])
data = [10, 20, 30]

for elem in data:
    print(elem)

実行結果

初期化についての注意

すでに説明したように、配列を使用する際には、

data = [1, 2, 3]

のように書く。

しかし、 data を定義する に、

data[0] = 1.2

とはできない。

プログラム中で配列の要素を追加したい場合は、

data = []        # data は(空の)配列である
data.append(10)

のように、 配列.append(要素) と書く。 これはこの配列 (の最後) に要素を追加する、という意味である。

このときも、

data = []
data[0] = 10    # エラー!

とは書けないので注意すること。

つまり:

  • すでに存在する配列の要素の書き換えは data[0] = 1.2 などとできる

  • まだ存在しない配列の要素は特別な方法 (append() など1) でしか追加できない

append() はすでに定義してある配列にも使える。 つまり、

data = [10, 20, 30]
data.append(40)

print(data)

とすると、 [10, 20, 30, 40] が表示される。

以下のプログラムを実行してみよ。 なぜそのような結果が得られたか考えてみよ。

data = []

for i in range(10):
    data.append(i * 10)

print(data)

実行結果

(発展) 配列のコピー

少々高度な内容になるが、ひっかかりやすい点なので説明しておく。 最初は流し読み程度でよい。

「配列のコピー」と言う場合には注意が必要である。 ある配列のコピーを作りたくて次のように書くと、おそらく期待した結果にならない。

array1 = [1, 2, 3]
array2 = array1

このとき、 array1 の最初の要素を書きかえたいとする。

array1[0] = 2

この時何が起こるか見てみよう。

以下のプログラムを実行すると何が起こるか (表示されるか) 考えよ。 その後で、実際に実行してみよ。

array1 = [1, 2, 3]
array2 = array1

print("Initial values")
print(array1)
print(array2)

array1[0] = 2

print("After change")
print(array1)
print(array2)

実行結果

このとき、 array1 のみが変更されること、つまり

[2, 2, 3]
[1, 2, 3]

という結果が得られることを期待するであろうが、実際には array2 まで変更されてしまっている。 何が起こっているのだろうか。

これはホワイトボードで説明すると、配列用のホワイトボードについている「名前」にもう一つの名前を付けていることになる2

/images/whiteboard-array-empty.png

従って、配列をコピーするには、まず新しい配列を作成し、要素を一つずつコピーする、という手順が必要になる。 実際に配列のコピーを作成する方法にはいくつかあるが、ここでは最も素朴な方法のみ紹介する。

array1 = [1, 2, 3]
array2 = []

for elem in array1:
    array2.append(elem)

# または:
# for i in range(len(array1)):
#     array2.append(array1[i])

以下のプログラムを実行すると何が起こるか (表示されるか) 考えよ。 その後で、実際に実行してみよ。 上の練習問題と比較し、その違いを確認せよ。

array1 = [1, 2, 3]
array2 = []

for elem in array1:
    array2.append(elem)

# または:
# for i in range(len(array1)):
#     array2.append(array1[i])

print("Initial values")
print(array1)
print(array2)

array1[0] = 2

print("After change")
print(array1)
print(array2)
実行結果

関数と配列

Python では関数の引数や戻り値に配列を使うことができる。

次は配列を引数として受けとる関数の例である (返り値は通常の数値)。

def sum_array(arr):
    summation = 0
    for i in range(len(arr)):
        summation += arr[i]
    return summation

data = [10, 20, 30]
print(sum_array(data))

このプログラムを入力して実行してみよ。

実行結果

練習問題

さて、これまでのまとめとして、次の練習問題をやってみよう。 少なくとも一つ目の問題は実際にやってみて欲しい。

引数として配列を受け取り、その 平均 を求め、それを返す関数を作成せよ。 また、データーとして data = [71, 80, 89] を与え、この関数を用いこのデーターの平均値を求めよ。

実行結果

引数として配列を受け取り、その 分散 を求め、それを返す関数を作成せよ。 また、データーとして data = [71, 80, 89] を与え、この関数を用いこのデーターの分散を求めよ。

実行結果

まとめ

ここでは配列について学んだ。

  • 配列とはデーターのまとまりである

  • 配列は data = [1, 2, 3] などで定義できる

  • 各要素は添字によって指定できる

  • 配列の添字は 0 から始まる

  • 配列の要素数は len(配列) として取得できる


1

他にもあるが、この文書では扱わない。

2

この説明はあまり正しくない。正確に知るにはもうすこし高度な知識が必要となるため、ここではこの程度の説明としておく。