【2分解説】Pythonのデータ構造の基礎を深堀り

  • 2023年7月13日
  • 2023年7月14日
  • Python

変数には1つのデータを入れられるというのが原則なのですが、複数のデータをひとまとまりで持つこともできます。
これを「データ構造」と読んでおり、特にPythonは高い柔軟性で持つことが可能です。

ここでは、2分で「データ構造」を理解できるようにまとめましたので、ぜひ参考としてみてください。

リストとは?

リストは変更可能なデータ構造(ミュータブル)となっており、あらゆる型のデータを要素として持つことが出来ます

要素の追加や削除はもちろん、並べ替えやリストの位置検索も可能です。

リストの定義と参照方法

# 数値のリスト
numbers = [1, 2, 3, 4, 5]
# 文字列のリスト
sports = ['baseball', 'soccer', 'basketball', 'tennis']
# 異なるデータ型の混在
mixed = [1, ['ichiro',51],'two',['ohtani',17], 3.0, ['oh', 1]]
# 空のリスト
data_list = []

print('数値リストの3番目要素=' + str(numbers[2]))
print('文字列リスト=' + str(sports))
print('混在パターンの参照=' + str(mixed[1][0]))

リストで使える主なメソッド

append

# Case1:リストの末尾に要素を1つ追加する。
data_list.append('a')
print('Case1=' + str(data_list))

extend

# Case2:リストの末尾に要素を複数追加する。
data_list.extend(['b', 'c', 'd'])
print('Case2=' + str(data_list))

insert

# Case3:要素の間に別の要素を追加する。
data_list.insert(2, 'A')
print('Case3=' + str(data_list))

index

# Case4:要素の位置を検索する
# 見つからなかった場合はValueErrorとなる。
pointer = data_list.index('c')
print('Case4=' + str(pointer))

try:
    pointer = data_list.index('Z')
    print('Case4=' + str(pointer))
except ValueError:
    print('ValueError')

clear

# Case5:リストの要素をすべて削除
data_list.clear()
print('Case5=' + str(data_list))

remove

data_list = ['a', 'b', 'c', 'd']
# Case6:一部の要素をリストから削除
try:
    data_list.remove('b')
    print('Case6=' + str(data_list))
    data_list.remove('Z')
except ValueError:
    print('ValueError')

pop

# Case7:特定の位置の要素をリストから取り出す
# 空のリストから取り出そうとしたら、IndexErrorとなる。
data_list.pop()
print('Case7=' + str(data_list))

data_list.clear()
try:
    data_list.pop()
except IndexError:
    print('IndexError')

count

data_list = ['a', 'a', 'b', 'c', 'd', 'd', 'd']
# Case8:要素の数をカウントする
count_ret = data_list.count('d')
print('Case8.1=' + str(count_ret))

# 該当しない要素をカウントした場合は0になる
count_ret = data_list.count('A')
print('Case8.2=' + str(count_ret))

sort

data_list = [2, 4, 9, 1, 3, 6, 8]
# Case9:リスト内の要素をソート(昇順)する
data_list.sort()
print('Case9.1=' + str(data_list))

# 引数として「reverse=True」をつけると降順になる
data_list.sort(reverse=True)
print('Case9.2=' + str(data_list))

タプルとは?

タプルはリストとは真逆で、変更出来ないデータ構造(イミュータブル)となっています。
あらゆる型のデータを要素として持つことが出来ますが、一度定義すると変えられないという特徴を持っているため、変更しないで持っておきたいデータを管理するのにお勧めです。
更新も削除もできません。

タプルの定義と参照方法

タプルは、カッコ( )で括る、もしくはカッコなしの形で定義すると、それとして認識されます。
リストの場合は、こちらのカッコ{ }で括る仕様となっていましたので、この違いがあるということを抑えておきましょう。
ここが曖昧だと、思わぬバグを引き起こす可能性が出てきます。

data_tuple1 = (1,'a',3.0)
data_tuple2 = 1,'a',3.14
data_tuple3 = (4,)
data_tuple4 = 4,

print(data_tuple1[0])
print(data_tuple2[-1])

最後尾にカンマが付いてるのはなに?

なお、要素を1つだけ定義するときに、最後尾にカンマをつけていますが、これは通常のカッコとの違いを認識させるための仕様となりますので、これも押さえておきましょう。

要素の参照について

要素を参照する場合、先頭からの参照は0からはじまりますが、後方からはじまる場合は-1からはじまります。
この違いがあることも押さえておくと、データ参照するときに便利なのでお勧めです。

タプルのデータスライシング

タプルのデータは要素の増減や変更が出来ませんが、一部のみ取り出すといったことが可能で、スライシングと呼んでいます。

sample_tuple = ('a','b','c','d','e')

print(sample_tuple[2:4])
print(sample_tuple[:3])
print(sample_tuple[2:])
print(sample_tuple[::3])

# === 出力結果 ===
# ('c', 'd')
# ('a', 'b', 'c')
# ('c', 'd', 'e')
# ('a', 'd')

範囲を指定したスライシングで注意すべきなのは、どこまで抽出するかを指定する数字
指定した最後尾の数字から、1引いた要素の内容までが抽出されますので注意しましょう。

タプル同士の結合

タプル単独の内容は変更不可ですが、他のタプルとの結合は可能です。

tuple_union1 = ('a', 'b', 'c')
tuple_union2 = ('d', 'e', 'f')

result = tuple_union1 + tuple_union2

print(result)
# ('a', 'b', 'c', 'd', 'e', 'f')

タプルのアンパック

タプルに入った要素をそれぞれの変数に分解することができ、これをアンパックと呼んでいます。

unpack_test = ('1', '2', '3')

one, two, three = unpack_test

print(one)
print(two)
print(three)

ディクショナリー(辞書)とは?

ディクショナリー型は、キー(key)と値(value)を連携させるタイプの構造体で、キーを指定することで連携されている値を取得することができるものです。
「従業員の名前を指定すると職員番号が分かる」というようなイメージを持つと分かりやすいかもしれませんね。

ディクショナリーの定義と参照方法

ディクショナリーは波カッコ { }で括り、キーと値をコロンで区切ったデータをカンマで設定していきます。

employee_info = {
    '田中':123,
    '山本':124,
    '小林':125,
    '加藤':126,
}

print(employee_info['田中'])
print(employee_info['山本'])
# === 出力結果 ===
123
124
値(value)は変更できますが、キー(key)は変更できない点を抑えておきましょう。

値の取得方法について

先ほど基本的なデータ取得方法をお見せしていますが、実はこの方法だと、存在しないkeyを指定したときにkeyErrorが発生します。
try Exceptを使ってエラー処理をすればいいという考え方もありますが、エラーを回避する取得方法としてgetメソッドを使うという手もありますので、ご紹介しておきます。

employee_info = {
    '田中':123,
    '山本':124,
    '小林':125,
    '加藤':126,
}

print(employee_info.get('田中'))
print(employee_info.get('高橋'))

# === 出力結果 ===
123
None
設定されていないキーを指定するとNoneが返ってきます。

新たなキーの追加と削除は?

ディクショナリー型のデータ構造の操作はとても簡単で、追加と削除も容易に行えます。
追加は存在しないキーを指定して値を入れるだけですし、削除はdelステートメントを使って該当のキーを指定するだけなので、簡単ですね。
なお、内容をすべて削除する場合はclearメソッドを使います。

employee_info = {
    '田中':123,
    '山本':124,
    '小林':125,
    '加藤':126,
}

employee_info['中野'] = 201
print(employee_info)

del employee_info['山本']
print(employee_info)

# 複数削除する場合
del employee_info['山本'], employee_info['小林']
print(employee_info)

# 内容をすべて削除する場合
employee_info.clear()
print(employee_info)

# === 出力結果 ===
{'田中': 123, '山本': 124, '小林': 125, '加藤': 126, '中野': 201}
{'田中': 123, '小林': 125, '加藤': 126, '中野': 201}
{'田中': 123, '加藤': 126, '中野': 201}
{}
追加されたキーは、必ず最後尾に追加されます。

その他のメソッド

この他に使えるメソッドとしては、keysメソッド・valuesメソッド・popメソッドがあります。

keysメソッド

ディクショナリーに定義されているキー(key)をすべて抽出するメソッドです。
キーの中身を確認して、どのキーの値を取得するかという場面でつかえそうです。

employee_info = {
    '田中':123,
    '山本':124,
    '小林':125,
    '加藤':126,
}

emp_key = employee_info.keys()
print(emp_key)

# === 出力結果 ===
dict_keys(['田中', '山本', '小林', '加藤'])

valuesメソッド

ディクショナリーに定義されている値(value)をすべて抽出するメソッドです。
in文と複合で使うと、その値が存在するかも確認できます。

employee_info = {
    '田中':123,
    '山本':124,
    '小林':125,
    '加藤':126,
}

emp_val = employee_info.values()
print(emp_val)
print(123 in emp_val)
print(999 in emp_val)

# === 出力結果 ===
dict_values([123, 124, 125, 126])
True
False
in文を使うとBoolean型の戻り値が返ってきます。

集合(セット)とは?

配列のようにindexを持たないデータ構造のことです。
indexという概念がない分、同じ値を持つことが出来ないという制約もあるので、同じ値を持ちたくないという場合に使いやすいデータ構造となっています。

集合の定義と参照方法

集合は波カッコ{ }で定義する形となります。
ただ、出力してみると、元々定義した並びとは異なる形となります。
これはインデックスがないためであって、出力する度にランダムに変わるため、集合のデータ構造にどんな要素が入っているかの確認が必要となります。

alphabets = {'a','b','c','d','e'}
print(alphabets)

# === 出力結果 ===
{'e', 'c', 'b', 'a', 'd'}

その時に参照するようになるかと思いますが、確認のケースとしては

  • 共通する要素の確認
  • ユニークな要素の確認
  • 条件にはまる要素の確認

といったことが上げられます。

要素の確認方法

集合演算を使った共通要素の確認

集合演算…という難しそうな言葉を使うと拒否感が出る方もいらっしゃるかと思いますが、要するに、集合のデータ構造同士を掛け算することで、共通の要素が見つかるというものです。

alphabets_set1 = {'a','b','c','d','e'}
alphabets_set2 = {'b','c','w','z'}

result = alphabets_set1 & alphabets_set2
result2 = alphabets_set1.intersection(alphabets_set2)

print(result)
print(result2)
# === 出力結果 ===
{'c', 'b'}
{'c', 'b'}

集合で構成されたデータ同士をアンド(&)で積演算すると、共通したデータ集合をつくることができます。
この手法で共通要素を確認することが可能です。
※intersectionメソッドで積演算することも可能です。

ユニークな要素の確認

あらかじめ定義された集合データに同じ要素が複数入っていた場合でも、setメソッドを使って別の変数にデータを移すと、ユニークの状態になって要素が戻ってきます。
これでユニークな形で要素を確認することが出来ます。

alphabets_set = {'a','b','b','c','d','e','e'}

alphabets = set(alphabets_set)
print(alphabets)

# === 出力結果 ===
{'b', 'e', 'a', 'c', 'd'}

条件にはまる要素の確認

条件にハマる要素(特定の要素)を確認するには、inキーワードを使用します。

alphabets = {'a','b','c','d','e'}
print('a' in alphabets)
print('z' in alphabets)

# === 出力結果 ===
True
False

要素が入っていればTrue、入っていなければFalseが返ってくる形となります。

要素の追加・削除手順は?

集合のデータ構造に要素を追加するためには、addメソッドを使い、逆に削除するためにはremoveメソッドを使う形となります。

alphabets_set = {'a','b','b','c','d','e','e'}

alphabets_set.add('z')
print(alphabets_set)

alphabets_set.remove('b')
print(alphabets_set)

# === 出力結果 ===
{'b', 'e', 'd', 'c', 'a', 'z'}
{'e', 'd', 'c', 'a', 'z'}

なお、要素をすべて削除する場合はclearメソッドを使ってください。

alphabets_set.clear()
print(alphabets_set)

# === 出力結果 ===
set()

その他に使える集合演算

他にも集合データ構造同士を結合したり、共通要素を省いて、ユニークな要素のみを残すことも出来たりしますので、参考にしてみてください。

集合演算(union)

集合データ構造同士を結合する方法としてunionメソッドを使うというものがあります。
“|”を使って結合することも可能です。

alphabets_set1 = {'a','b','c','d','e'}
alphabets_set2 = {'d','e','f','g','h'}

result = alphabets_set1.union(alphabets_set2)
print(result)

result2 = alphabets_set1 | alphabets_set2
print(result2)

# === 出力結果 ===
{'a', 'b', 'c', 'f', 'e', 'g', 'h', 'd'}
{'a', 'b', 'c', 'f', 'e', 'g', 'h', 'd'}

集合演算(difference・symmetric_difference)

共通する部分を省いて左辺のユニーク要素だけを残すのがdifferenceメソッド、両辺のユニーク要素を残すのがsymmetric differenceメソッドとなります。
differenceメソッドは”-“、symmetric differenceメソッドは”^”でも対応可能です。

alphabets_set1 = {'a','b','c','d','e'}
alphabets_set2 = {'d','e','f','g','h'}

result = alphabets_set1.difference(alphabets_set2)
print(result)

result2 = alphabets_set1 - alphabets_set2
print(result2)

result3 = alphabets_set1.symmetric_difference(alphabets_set2)
print(result3)

result4 = alphabets_set1 ^ alphabets_set2
print(result4)

# === 出力結果 ===
{'c', 'a', 'b'}
{'c', 'a', 'b'}
{'h', 'b', 'c', 'f', 'g', 'a'}
{'h', 'b', 'c', 'f', 'g', 'a'}

集合演算(symmetric_difference_update)

さらに、両辺のユニーク要素を抽出して、左辺のデータ内容を更新するのが、symmetric_difference_updateとなります。
symmetric_differenceとの違いは、新たな集合体をつくるか、左辺の集合体のデータ内容を更新するかで違いますので、注意が必要です。

alphabets_set1 = {'a','b','c','d','e'}
alphabets_set2 = {'d','e','f','g','h'}

result1 = alphabets_set1.symmetric_difference(alphabets_set2)
print(result1)

alphabets_set1.symmetric_difference_update(alphabets_set2)
# alphabets_set1 ^= alphabets_set2 でも可
print(alphabets_set1)

# === 出力結果 ===
{'c','h','b','g','a','f'}
{'c','h','b','g','a','f'}

以上が、Pythonで扱うデータ構造の基礎となります。
ぜひこの内容を参考に自分自身でも研究してみてくださいね!

最新情報をチェックしよう!

Pythonの最新記事8件