リスト内包表記についての覚え

**目次から飛んで途中から見る場合、対応する原型は直上にあるものを確認されたい。**

#環境
・macOS High Sierra 10.13.6
・Python 3.8
・エディタ Atom
　・AtomはデフォルトでPythonの実行をサポートしていないので、必要なパッケージをダウンロードする必要がある

#原型1
まずは、実際にリスト内包表記を試行する前の形を確認しておく。Python公式ドキュメントでは、squareになっているので本当にちょっとだけ書き換えて、簡単のために0~9までの整数の立方数を格納するcubesというリストを考える。
解説は不要のことと思う。

```.py
cubes = []
for x in range(10):
    cubes.append(x**3)
print(cubes)
```

```実行結果.
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
```

##リスト内包表記での記述
実行結果は省略する。
```.py
cubes = [x**3 for x in range(10)]
print(cubes)
```
意味で書く以下の通り。

```.py
リスト = ［変数を扱った何かしらの操作 for シーケンスなどから取り出された要素を格納する変数 in シーケンスやイテレート可能なオブジェクト］
```

##関数をかませる場合
シーケンスやイテレート可能なオブジェクトから得た要素に対してもう少し複雑な操作を行いたい場合や、それらを基に何かの操作をして、要素がリストに新しく格納するオブジェクトの直接的なパラメータになるわけではない場合は、（より簡便に言うなら）関数を噛ませたいと思うことがあるかもしれないので、その方法も考えておく。

```.py
def func(arg):
    return arg**3

cubes = [func(x) for x in range(10)]
print(cubes)
```
意味的には、「**シーケンスから一つずつ得た要素を都度都度関数に入れて、結果をリストに追加する**」といったところ。

#原型2
シーケンスやイテレート可能なオブジェクトからひとつひとつ得た要素に、なんのそ操作もせずにリストに加えたい場合があるかもしれない。例えば以下のように自然数のリストを作りたい場合を考える。

```.py
natural_num = []
for n in range(1,10):
    natural_num.append(n)
print(natural_num)
```

```実行結果.
[1, 2, 3, 4, 5, 6, 7, 8, 9]
```

##リスト内包表記での記述

```.py
natural_num = [n for n in range(1,10)]
```
要素を関数に入れたり計算させてるわけではないので、２回登場する一時的な変数であるnが何なのかわかりにくいが、原型１を踏まえれば問題はない。
こんなばかばかしい構文を書くことが実際にあるのか謎であるかもしれないが、個人的には行ごとにレコードが別れて記述されたcsvファイルを読み込んで、それをリストに落とし込むときなどに活用した。リスト内包表記のことを知っていないと読み解けないかもしれない。

#原型3
シーケンスやイテレート可能なオブジェクトの要素を検討して、**追加するかどうか判定を差し挟んでからリストに追加したい場合**があるかもしれない。
rangeを利用するなら、先頭の数字がわかれば、あとはステップ数を指定することで実現できるが、ここではあえてif文を使って、0~99の整数のうち、7で割ると余りが1になる整数のリストを作る。

```.py
list = []
for x in range(100):
    if (x % 7 == 1):
        list.append(x)
print(list)
```

```実行結果.
[1, 8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99]
```
##リスト内包表記での記述
以下のように、基本的な記述に連結するようにif節と追加条件を書けばいい。

```.py
list = [x for x in range(100) if x % 7 == 1]
```

##リストへの追加判定に関数を利用する
追加条件はBoolean値を取るので、そのような値が返る関数を利用すれば、その関数で置き換えることができる。追加条件が複雑化した場合はこちらのほうが可読性にも記述性にも優れているかもしれない。

```.py
def func(n):
    if (n % 7 == 1):
        return True
    else:
        return False


list = [x for x in range(100) if func(x)]
print(list)
```

#原型4
3つある要素をから2つを選んで順番を区別する組み合わせを列挙する場合を考える。実際にはmathモジュールとかを使えばいいだろうけど、練習のためにリスト内包表記を考える。

```.py
list = ['A','B','C']

permutation = []
for i in list:
    for j in list:
        if (i != j):
            permutation.append([i,j])
print(permutation)
```

```実行結果.
[['A', 'B'], ['A', 'C'], ['B', 'A'], ['B', 'C'], ['C', 'A'], ['C', 'B']]
```
##リスト内包表記での記述

```.py
list = ['A','B','C']

permutation = [(x,y) for x in list for y in list if x != y]
```
if文を入れた場合の発展型であるが、forのところで区切れていて２個の変数に同時に代入がされていることがわからないと、何をやっているのか見えてこないかもしれない。

#おまけ
ネストされた行列の行と列を入れ替えたい場合はそうそうないかもしれないが、公式ドキュメントにもあるので記述しておく。

```.py
matrix = [
    [1,2,3,4],
    [5,6,7,8],
    [9,10,11,12]
    ]

new_matrix = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
print(new_matrix)
```

```実行結果.
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
```

#リスト内包表記を利用することの利点
-リソースを節約できる。
-「リスト内包表記」を知っている者にとっては、可読性に優れている。
-大括弧（[]）でくくっているので、オブジェクト自体として、リストを操作しているのであると直感的に分かる

#参考文献
-[5.1.3. リストの内包表記 - 5. データ構造](https://docs.python.org/ja/3.8/tutorial/datastructures.html#list-comprehensions)