製薬企業研究者がPythonのデータ構造についてまとめてみた

# はじめに

ここでは、Python初心者向けに「データ構造」について解説します。
Python3系の使用を想定しています。

# リスト (list)

## リストの作成

```python:list_1.py
list_int = [1, 2, 3, 4, 5] # 要素が全て数値のリスト
print(list_int)

list_str = ['Python', 'R', 'Java', 'Ruby', 'PHP'] # 要素が全て文字列のリスト
print(list_str)

list_bool = [True, False, True, True, False] # 要素が全てブール値のリスト
print(list_bool)

list_mix = [1, 2, 3, 4, 'GO'] # 1つのリストの中に複数のデータ型の要素を混在させることもできる。
print(list_mix)

list_2d = [[1, 2], [3, 4]] # 2次元以上のリストも作成できる。
print(list_2d)

list_empty = [] # 空のリストを作成する。
print(list_empty)
```

連続する数値をリストに格納する場合は、以下のような書き方もできる。

```python:list_2.py
list_range = list(range(1, 100)) # range(m, n) は、mからn-1の連続する整数を指し、list型に変換している。
print(list_range)

list_range_odd = list(range(1, 100, 2)) # 1刻みでなくてもできる。
print(list_range_odd)
```

## リストの要素の値の参照

```python:list_3.py
list_int = [1, 2, 3, 4, 5]

list_int_1 = list_int[1] # インデックス1（2番目）の要素の値を参照する。
print(list_int_1)

list_int_0 = list_int[0] #インデックス0（1番目）の要素の値を参照する。
print(list_int_0)

list_int_minus1 = list_int[-1] # 後ろから数えて1番目の要素の値を参照する。
print(list_int_minus1)

list_2d = [[1, 2], [3, 4]]

list_2d_0 = list_2d[0]
print(list_2d_0) # インデックス0（1番目）の要素の値を参照する。

list_2d_0_0 = list_2d[0][0]
print(list_2d_0_0) # インデックス0（1番目）の中のインデックス0（1番目）の要素の値を参照する。

# 要素が入っていないインデックス値を指定すると、エラーになる。
list_int_12 = list_int[12]
print(list_int_12)

list_int_slice1to3 = list_int[1:3] # スライス（特定の区間の要素を連続して取り出す）
print(list_int_slice1to3)
```

文字列もリストのように扱えます（前からX文字目を参照する、などといったことができます）。

```python:list_4.py
var_str = 'abcde'
print(var_str[3])
print(var_str[1:3])
```


## リストの値の更新
```python:list_5.py
list_int = [1, 2, 3, 4, 5]
list_int[2] = 6 # インデックス2の値を更新する。
print(list_int)
```


## in演算子

in演算子を用いることで、ある値がリストの要素として含まれるかどうかを判定できます（含まれる場合は`True`、含まれない場合は`False`が返されます）。

```python:list_6.py
list_int = [1, 2, 3, 4, 5]
print(2 in list_int) #Trueが出力される
print(12 in list_int) #Falseが出力される
```

## リストの要素の数の取得

`len()`を使うと、リストの要素の数を取得することができます。

```python:list_7.py
list_int = [1, 2, 3, 4, 5]
list_int_length = len(list_int)
print(list_int_length)
```


以下のように、文字列に対しても同様に使えます（文字数を数えることができます）。

```python:list_8.py
var_str = 'abcde'
var_str_length = len(var_str)
print(var_str_length)
```

## リストの演算

```python:list_9.py
ones = [1] * 5 # 同じリストを指定回数だけ繰り返す。
print(ones)

rep = [1, 2, 3] * 4
print(rep)

nums_1 = [1, 2, 3]
nums_2 = [4, 5]

nums_3 = nums_1 + nums_2 # リストを結合する。
print(nums_3)
```


## リストのメソッド

```python:list_10.py
nums = [1, 2, 3, 4, 5]

nums.append(6) # リストの最後に要素を追加する。
print(nums)

nums.extend([7, 8, 9]) # リストの最後にイテラブルの要素全てを追加する。
print(nums)

nums.insert(5, 10) #インデックス5番目の要素の前に要素10を追加する。
print(nums)

nums.remove(10) # 要素10を削除する。
print(nums)

print(nums.pop(1)) # インデックス1番目の要素を削除して返す。

print(nums.pop()) # インデックス番号を指定しなかった場合は末尾の要素を削除して返す。

print(nums.index(5)) # 指定した要素を探し、その位置を返す。

print(nums.count(3)) #　指定した要素の出現回数を返す。

nums.sort(key=None, reverse=False) # リストを並べ替える。keyで比較の関数を指定できる。reverse=Trueにすると、大きい順にソートする。
print(nums)

nums.reverse() # インプレース演算で逆順にする。
print(nums)

nums_rev = nums[::-1] # 逆順にする。
print(nums_rev)

nums_copy = nums.copy() # コピーを作成する。
print(nums_copy)

del nums[6] # 指定したインデックス番号の要素を削除する。
print(nums)

nums.clear() # リストの全ての要素を削除する。
print(nums)
```

# タプル (tupple)

## タプルの作成

```python:tupple_1.py
tupple_int = (1, 2, 3, 4, 5)
print(tupple_int)
```


## タプルの要素の値の参照

```python:tupple_2.py
tupple_int_1 = tupple_int[1] # インデックス1（2番目）の要素の値を参照
print(tupple_int_1)

tupple_int_0 = tupple_int[0] #インデックス0（1番目）の要素の値を参照
print(tupple_int_0)

tupple_single = (1,) # 要素数 1 のタプル
print(tupple_single)
```

タプルの値の更新はできません（ここがリストとの大きな違いです）。
逆に言えば、処理の途中で更新したくない値を配列形式にする場合にタプルを使うと良いです。

```python:tupple_3.py
tupple_int = (1, 2, 3, 4, 5)
tupple[2] = 6 # エラーになる。
```


# 辞書 (dictionary)

## 辞書の作成

```python:dictionary_1.py
dict_human = {'身長': 200, '体重': 100, 'BMI': 25} # {key: value}という形で作成する。
print(dict_human)

dict_empty = {} # 空の辞書を作成する。
print(dict_empty)
```


## 辞書の要素の値の参照

```python:dictionary_2.py
dict_human = {'身長': 200, '体重': 100, 'BMI': 25}
dict_human_height = dict_human['身長']
print(dict_human_height)
```


## 辞書の要素の値の更新

```python:dictionary_3.py
dict_human = {'身長': 200, '体重': 100, 'BMI': 25}
dict_human['身長'] = 180
print(dict_human)
```


## 辞書への新しいアイテムの追加

辞書にないキーを指定して値を代入した場合は、新しくキーが追加されます。

```python:dictionary_4.py
dict_human = {'身長': 200, '体重': 100, 'BMI': 25}
dict_human['性別'] = '男'
print(dict_human)
```


## 辞書のメソッド

```python:dictionary_5.py
dict_human = {'身長': 200, '体重': 100, 'BMI': 25}

print(dict_human.keys()) # 辞書に存在するキーの一覧を返す。

print(dict_human.values()) # 辞書に存在する値の一覧を返す。

print(dict_human.items()) # 辞書に存在するキーと値の組み合わせの一覧を返す。

print(dict_human.get('身長', '不明')) # 第一引数で指定したキーがある場合は、その値を返す。
print(dict_human.get('血液型', '不明')) # 第一引数で指定したキーがない場合は、第二引数で指定した値を返す。

dict_human_pop = dict_human.pop('BMI') # 指定したキーを削除して返す。
print(dict_human_pop) # 削除したキーの値を返す。
print(dict_human) # 削除後の辞書を返す。

del dict_human['体重'] # 指定したキーを削除する。
print(dict_human)

dict_human.clear() # 辞書の全ての要素を削除する。
print(dict_human)
```


# 集合 (set)

## 集合の作成

```python:set_1.py
set_int = {1, 2, 3, 4, 5}
print(set_int)

set_empty = set()
print(set_empty)
```

## 集合のメソッド
```python:set_2.py
set_int = {1, 2, 3, 4, 5}

set_int.add(6) #かっこ内のアイテムを追加する。
print(set_int)

set_int.update([7, 8, 9, 10]) #かっこ内のイテラブルの要素全てを追加する。
print(set_int)

set_int.pop() # いずれかの要素を削除して返す。
print(set_int)

set_int.remove(10) # かっこ内のアイテムを削除する。指定されたアイテムが存在しないとエラーになる。
print(set_int)

set_int.discard(10) # かっこ内のアイテムを削除する。指定されたアイテムが存在しなくてもエラーにならない。
print(set_int)

set_int_2 = {1, 2, 3}

print(set_int.isdisjoint(set_int_2)) # set_int_2と共通する要素がなければTrueが返される。

print(set_int.issubset(set_int_2)) # set_int_2の部分集合であればTrueが返される。

print(set_int.issuperset(set_int_2)) # set_int_2が部分集合であればTrueが返される。

print(set_int.difference(set_int_2)) # set_int_2の要素を削除した集合（差集合）を返す。

set_int.difference_update(set_int_2) # set_int_2との差集合に置き換える。
print(set_int)

print(set_int.intersection(set_int_2)) # set_int_2との共通の集合（積集合）を返す。

set_int.intersection_update(set_int_2) # set_int_2との積集合に置き換える。
print(set_int)

print(set_int.symmetric_difference(set_int_2)) # 片方にしか含まれない要素の集合（対称差）を返す。

set_int.symmetric_difference_update(set_int_2) # set_int_2との対称差に置き換える。
print(set_int)

print(set_int.union(set_int_2)) # set_int_2の要素を追加した集合（和集合）を返す。

set_int.update(set_int_2) # set_int_2との和集合に置き換える。
print(set_int)

set_int_copy = set_int.copy()
print(set_int_copy)

set_int.clear()
print(set_int)
```

## 集合の判定

```python:set_3.py
set_1 = {3, 4, 5}
set_2 = {1, 2, 3, 4, 5}

print(set_1 <= set_2) # set_1がset_2の部分集合かどうか
print(set_1.issubset(set_2) or set_2.issuperset(set_1))

print(set_1 < set_2) # set_1がset_2の部分集合で、同一の集合でないか
print(set_1 <= set_2 and set_1 != set_2)

print(set_1 == set_2) # set_1とser_2が同一の集合かどうか
print(set_1 <= set_2 and set_1 >= set_2)

print(3 in set_1) # アイテムが集合に含まれるかどうか
```


## 集合の演算

```python:set_4.py
set_1 = {3, 4, 5}
set_2 = {1, 2, 3, 4, 5}

print(set_1 - set_2) # 差集合
print(set_1.difference(set_2))

print(set_1 & set_2) # 積集合
print(set_1.intersection(set_2))

print(set_1 | set_2) # 和集合
print(set_1.union(set_2))

print(set_1 ^ set_2) # 対称差
print(set_1.symmetric_difference(set_2))
```


# まとめ

ここでは、Pythonにおけるデータ型として「リスト（list）」「タプル（tupple）」「辞書（dictionary）」「集合（set）」について解説しました。
とりあえずは、「リスト」と「辞書」が理解できていればいいかなと思います。


# 参考資料・リンク

[プログラミング言語Pythonとは？AIや機械学習に使える？](https://pharma-engineer.com/basic-programming/python-summary/)