第二章データ構造と配列
いよいよプログラミングっぽいところであり、?が浮かびがちな章に入ります。
【出典】「新・明解Pythonで学ぶアルゴリズムとデータ構造」
前回まで記事はこちら
2-1データ構造と配列
最初はデータ構造や配列とはなんぞやというところから始めるみたいですね。
配列の必要性
急に配列の必要性なんて言われても…。そもそも配列がピンとこない私には話が飛躍している気がするので…。
配列:コンピューターのプログラミング言語における、データ形式の一。同じ型のデータの集合を意味し、個々のデータは変数の添え字で区別する。【出典】デジタル大辞泉
とのことでした。
以下のプログラムでは5人の生徒の点数を合計した値、平均した値を求めます。
#5人の点数を読みこんで、合計・平均点を表示
print('5人の点数の合計点と平均点を求めます。')
tensu1 = int(input('1番目の点数:'))
tensu2 = int(input('2番目の点数:'))
tensu3 = int(input('3番目の点数:'))
tensu4 = int(input('4番目の点数:'))
tensu5 = int(input('5番目の点数:'))
total = 0
total += tensu1
total += tensu2
total += tensu3
total += tensu4
total += tensu5
print(f'合計は{total}点です。')
print(f'平均は{total / 5}点です。')
さて、上記のコードでは、応用の利かない記述になっていることは明確です。
①人数を可変、②特定の点数を調べる/書き換え、③最低点と最高点を求める/ソートの3つを実現することで、有用性のあるプログラムといえます。そのためにはプログラムの作り方を変える必要があります。
まず、各生徒の点数をひとまとめにして扱えるようにします。それを実現するのが配列と呼ばれるデータ構造です。
配列はオブジェクトの格納庫であって格納された個々の変数は要素と呼ばれます。各要素には先頭から順番に0,1,2・・・の添字が与えられる。
配列は生成時に要素を自由に指定できるため①はクリアできます。また、要素数の増減も可能です。添字を使った式(tensu[2]など)でアクセスできるため②の実現も容易。ここの要素を自由にアクセスできる結果として③も実現できます。
こうやって考えると配列の考えは重要でプログラミングには欠かせないものということがわかりました。
#リストとタプル
pythonで配列を実現するのがリストとタプルです。いずれも高機能なデータのコンテナ(格納庫)です。
リスト:変更可能(ミュータブル)なlist型のオブジェクト。list関数を使うと文字列やタプルなど様々な型のオブジェクトをもとに、リストを生成できます。要素数が決まっており、要素の値は未定(空の情報)の時 None を使うことが可能。[]を使う。
タプル:組とも呼ばれる。要素を順序付けて組み合わせたもの。変更不能(イミュータブル)オブジェクトで、tuple型。()を使う。
v01 = 1 #1
v02 = (1) #1
アンパック:リストから要素の一括取り出しができる。
x = [1, 2, 3]
a, b, c = x
print(a,end = '')
print(b,end = '')
print(c,end = '')
#インデックス式によるアクセス
リストやタプル内の個々の要素をアクセスする際のキーとなるのが、インデックス。
[1,2,3,4,5,6,7]
先頭0 1 2 3 4 5 6 末尾(非負のインデックス)
先頭-7-6-5-4-3-2-1末尾(負のインデックス)
インデックス式
x = [11, 22, 33, 44, 55, 66, 77]
print(x[2])
print(x[-3])
x[-4] = 3.14 #要素の置換
print(x)
代入でコピーされるのは値でなく参照であるため、x[-4]の参照先がint型(44)からfloat型(3.14)に変わります。
なお、xがタプルだった場合は代入はエラーになります。(タプルは変更不能なため)
x[7] #存在しないインデックスの値は取り出せない
x[7] = 3.14 #存在しないインデックスへの代入による要素の追加は行われない
存在しない要素をアクセスするインデックス式を、左辺に置く代入によって、要素が新しく追加することはできません。
#スライス式によるアクセス
スライス:リストやタプル内の部分を連続あるいは一定周期で新しいリストあるいはタプルとして取り出すこと
スライス式による取り出し
s[i:j] ・・・s[i]からs[j-1]までの並び
s[i:j:k] ・・・s[i]からs[j-1]までのkごとの並び
s = [11, 22, 33, 44, 55, 66, 77]
s[0:6]
s[0:7]
s[0:7:2]
s[-4:-2]
s[3:1]
・iとjは、len(s)よりも大きければ、len(s)が指定されたものとみなされる。
インデックスとは異なり、正当な範囲外の値を指定してもえらーとならない。
・iが省略されるかNoneであれば、0が指定されたものとみなされる。
・jが省略されるかNoneであれば、len(s)がしていされたものとみなされる。
まとめると以下のようになります。
s[:]・・・すべて
s[:n]・・・先頭のn要素
s[i:]・・・s[i]から末尾
s[-n:]・・・末尾の-n要素
s[::k]・・・k-1個おき
s[::-1]・・・すべてを逆向き
※nが要素数を超える場合は全要素が取り出される。
コラム2-1 代入とイミュータブル(変更不能)/ミュータブル(変更可能) |
---|
変数には、格納済みの値とは異なる型の値を代入できます。
型にどんな種類があるかわかりませんが、できるそうです。
n = 5
id(n) #5のIDが参照される
n = 'ABC'
id(n) #ABCのIDが参照される
文字列の代入後にnの識別番号が変わります。(int型からstr型に更新)
変数への代入によってコピーされるのは参照先である識別番号(同一性)であって値ではないため、あらゆる型のオブジェクトを変数に代入できるそうです。
pythonの代入文は極めて多機能で、初めて使う名前の変数に値を代入するだけで、その名前の変数が自動的に用意される。それ以外にも多くの機能があるみたいです。
a, b, c =1, 2, 3
print(a)
print(b)
print(c)
x = 6
y = 2
x, y = y + 2, x + 3
print(x)
print(y)
n = 12
id(n)
n +=1 #nの値を1増やす
id(n) #識別番号が変更される
聞くだけだとたくさんの機能がある分覚えること多くて大変そうと思いますが、一見すると便利感あります。
型について、int型やstr型はいったん与えられた値が変更できないイミュータブルな型だそうで。(nの値は変更できるが12など数字自体の値(id)は変更できないため)
・ミュータブルな型:リスト、辞書、集合 など
・イミュータブルな型:数値、文字列、タプル など
pythonの代入の特性
・左辺の変数名が初出であれば、その変数を定義する。
・代入文は、値ではなく参照先(識別番号=同一性)を代入する。
・複数の代入が一括で可能。
とまとめられています。
具体的な記述で見れば
x + 17 は式。
x = 17 は文。
ということみたいです。
余談ですが、C,C++,javaなどは、 = は'右結合の演算子'として扱われるため
a = b = 1 は a = (b =1)
という解釈になるらしいです。(こちらの方が数学のイメージに近いですね)
pythonでは、= は演算子でないため、結合性は存在しません。
#データ構造
データ構造:構成要素との間に何らかの相互関係をもつデータの論理的な構成のこと。(つまり複数のデータが集まった構造だが、0個、1個もありうる)
イメージをしようと思うと結構難しいので私は「へー」程度の理解にしておこうと思います。
コラム2-2リストとタプル(その1) |
---|
x = [15, 64, 7, 3.14, [32, 55], 'ABC']
len(x) #[32, 55]は1つとしてカウントされる
min()やmax()はリストやタプルも引数として渡すことができる。
y = [2, 4, 5, 78, 98 ]
print(min(y))
print(max(y))
空リスト/空タプルの判定
空リスト、空タプルの判定は偽になります。
z = []
if z:
print("True")
else:
print("False")
z = []
if not z:
print("True")
else:
print("False")
値比較演算子による大小関係および等価性の判定
リストどうし/タプルどうしの大小関係および等価性の判定は、値比較演算子によって行えます。
次に示すのはいずれも真となる判定の例。
[1, 2, 3] == [1, 2, 3]
[1, 2, 3] < [1, 2, 4]
[1, 2, 3, 4] <= [1, 2, 3, 4]
[1, 2, 3] < [1, 2, 3, 5]
[1, 2, 3] < [1, 2, 3, 5] < [1, 2, 3, 5, 6]
インデックスが同じところどうしで判定が行われていき、条件が合えばTrueを返すようですね。
リストとタプルの共通点と相違点
リストとタプルの相違点は次の表のようになるようです。
Table 2C-1 |
---|
性質/機能 | リスト | タプル |
---|---|---|
ミュータブル | 〇 | × |
辞書のキーとして利用できる | × | 〇 |
イテラブルである | 〇 | 〇 |
帰属性演算子in演算子/not in 演算子 | 〇 | 〇 |
加算演算子+による連結 | 〇 | 〇 |
乗算演算子*による繰り返し | 〇 | 〇 |
累算演算子+=による連結代入 | 〇 | △ |
累算*=による繰返し代入 | 〇 | △ |
インデックス式 | 〇 | △ |
スライス式 | 〇 | △ |
len関数による要素数取得 | 〇 | 〇 |
min関数/max関数による最小値/最大値 | 〇 | 〇 |
sum関数による合計値 | 〇 | 〇 |
indexメソッドによる探索 | 〇 | 〇 |
countメソッドによる出現回数 | 〇 | 〇 |
del文による要素の削除 | 〇 | × |
appendメソッドによる出現回数 | 〇 | × |
clearメソッドによる全要素の削除 | 〇 | × |
copyメソッドによるコピー | 〇 | × |
extendメソッドによる拡張 | 〇 | × |
insertメソッドによる要素の挿入 | 〇 | × |
popメソッドによる要素の取り出し | 〇 | × |
removeメソッドによる指定値の削除 | 〇 | × |
reverseメソッドによるインプレースな反転 | 〇 | × |
内包表記による生成 | 〇 | × |
コラム2-3へ続く・・・ |
以上で2章1節のお話が終わります。リストとタプルの使い分けとかいまいちわからんなあと思っているので、追々理解できたらいいなと思います。
ありがとうございました。