【Python】無名関数　Lambdaを使ったリストの便利なソート方法

#課題

リストをソートするとき"sorted関数"を使用して並び替えをしているのがオーソドックスな方法です。課題としてsorted関数を使用するとき、デフォルトの状態でソートを行うと文字順にソートされます。

文字列に含まれている数字、文字数など凝ったソートをする場合にはどうしたらいいか？
そういった凝ったソートを行うときなどに、keyにlambdaの条件を設定することで複雑なソートも可能になります。

はじめは無名関数Lambdaについて説明しますんで、知っている方はスキップを～



##無名関数 Lambda　について

通常は関数を定義するときに名前を付けなければなりません（当たり前ですが⋯）
関数は多くの行を要する処理を繰り返し使用する際に便利です。

通常、関数を定義する際には以下の文法で記述します。

```python:
def func(引数):
    return 戻り値
```

引数は入力したい値、戻り値は出力したい値と思って差し支えありません。

試しに関数を定義して使用してみると

```python:func.py
#二次関数を定義
def func(x):
    return x**2
#1～9まで二次関数の値を出力する
for i in range(1,10):
    print(func(i)," ",end="")

>>1  4  9  16  25  36  49  64  81

```

このように何度も同じ処理をする際に便利です。

次に無名関数　Lambdaの文法に触れていきましょう。

```python
lambda 引数:戻り値
```

このように lambdaを入れて引数と戻り値を定義します。
上記の二次関数をlambda関数を使用して記述するとこうなります。
↓

```python:lambda.py

func_lambda = lambda x:x**2 

for i in range(1,10):
    print(func_lambda(i)," ",end="")

>>1  4  9  16  25  36  49  64  81
```

こんな風に使用することができます。

##無名関数の何がいいの？

無名関数　関数を定義するのになんでわざわざlambdaを使うの？と疑問に持った人はいると思います。lambdaを使うことで一番のメリットは一回しか使わない関数を態々定義しなくてもいいところです。

繰り返し使わない関数は一回きりしか使わないときは、無名関数を使った場合では一行で書ける場合がほとんどです。

具体的にリスト型の変数に使う関数、map関数、filter関数()を使うときにとても便利です。

>- **map関数** リストに入っている要素すべてを、引数に設定した関数の戻り値にする関数

>- **filter関数** リストに入っている要素すべてを、関数の条件に合った物だけを要素として抽出する関数

ここではあまり詳しく記述しませんが、興味があれば各自で調べてください。


#本題　lambdaを使ったリストのソートの仕方

リストを使う場合sorted関数を使用します。引数にリスト型の変数のみだと、文字列順にソートされます。

```python:sorted.py

list1 = ["guitar","drums","bass","vocal","keyboard"]
list2 = sorted(list1)
print(list2)

>>['bass', 'drums', 'guitar', 'keyboard', 'vocal']
```

このように頭文字が若い順にソートされました。
第二引数に`reverse =True`を追加すると、順番が反転します。


```python:sorted.py

list1 = ["guitar","drums","bass","vocal","keyboard"]
list2 = sorted(list1,reverse = True)
print(list2)

>>['vocal', 'keyboard', 'guitar', 'drums', 'bass']
```

##文字数順にソートする

sorted関数の復習を終わったので、今度は無名関数を設定し、keyに追加していきます。
ここでは文字列の長さ順にソートしていきます。


```python:sorted.py

list1 = ["guitar","drums","bass","vocal","keyboard"]
list2 = sorted(list1,key=lambda x: len(x),reverse=True)
print(list2)

>>['keyboard', 'guitar', 'drums', 'vocal', 'bass']
```

ここで第二引数にkeyという文字が設定されています。ここに並び替えの基準となる関数を設定します。無名関数の引数は`len(x)`となっています。xとは個々のリストの要素を表しています。len関数とは文字列やリスト、辞書型変数の長さを出力する関数です。

よって並び替えられる基準は文字数になります。しかしこのままだと文字数が少ない順にソートされてしまうため`reverse=True`を引数に設定します。


##通し番号がついている要素をソートする

リストの要素に通し番号がついていて、それを基準にソートしたい場合


```python:sorted.py

import  re

list1 = ["001guitar","005drums","004bass","003vocal","002keyboard"]
list2 = sorted(list1,key=lambda x: int(re.match(r"(\d+).+",x).group(1)))

print(list2)

>>['001guitar', '002keyboard', '003vocal', '004bass', '005drums']
```

このときkeyに設定されている無名関数は`int(re.match(r"(\d+).+").group(1))`
となっています。`int()`で括っているため無名関数の戻り値はint型になっています。

int()の中をのぞいてみると正規表現で数字と任意の文字が付いた文字列にヒットするようになっています。その中からサブパターンである数字の部分を取り出し、キーに設定します。




##リストの要素がリスト型のソート

リストの要素がリスト型の場合は、キーに設定する際に中身のリストのどの要素をキー設定するかでソートの結果が変わってきます。


```python:sorted.py

XJapan = [["guitar","PATA"],["drums","YOSHIKI"],["bass","HEATH"],["vocal","ToshI"],["piano","YOSHIKI"],["guitar","SUGIZO"]]
list = sorted(XJapan,key=lambda x: x[1])

print(list)

>>[['bass', 'HEATH'], ['guitar', 'PATA'], ['guitar', 'SUGIZO'], ['vocal', 'ToshI'], ['drums', 'YOSHIKI'], ['piano', 'YOSHIKI']]

```

上記のソートで設定したキーはリストの要素のリストの中の二番目の値をキーに設定していあます。
無名関数　lambdaの戻り値はx[1]となっており、二番目の要素を基準にします。

また、x[1]の要素として`"YOSHIKI"`の部分が重複している要素があります。その場合、もう一つの要素であるx[0]の要素が優先されてソートされます。