sort、sorted、key

sorted

之前我們使用排序時是呼叫 list 內建的 sort function:

a = [3, 1, 2]
a.sort()
print(a)

但這樣 a 會被修改,如果我們希望保持 a 不變的話,要先對 a 做備份

a = [3, 1, 2]
b = a[:]     # [:] 代表取整個 a 的 slice
b.sort()     #
print(b)

這個時候我們可以使用 sorted(可迭代物件) 去處理

In [1]: a = [3, 1, 2]

In [2]: b = sorted(a)

In [3]: b
Out[3]: [1, 2, 3]

In [4]: a
Out[4]: [3, 1, 2]

sorted 也可以使用在 tuple 上

In [5]: a = (2, 1, 3)

In [6]: b = sorted(a)

In [7]: b
Out[7]: [1, 2, 3]

key 和 lambda

現在我們有一個 list of tuple,裡面每一項是 (姓名, 成績)。

In [8]: score = [('rilak', 59), ('melody', 100), ('hortune', 87)]

In [9]: score[0]
Out[9]: ('rilak', 59)

我們希望可以按照成績排序,但 tuple/list 的預設是按照「第一項」來排

In [11]: sorted(score)
Out[11]: [('hortune', 87), ('melody', 100), ('rilak', 59)]

In [12]: 'hortune' < 'melody' < 'rilak'
Out[12]: True

直接呼叫 sorted 去排序的結果會按照姓名來排,因為字母順序 'h' < 'm' < 'r' ,所以 horturn 在最前面,而 rilak 在最後面。

key function!

為了不直接比較元素的大小,我們要寫一個 key function 指定說:對於每一個在 list 裡面的元素,都要先經過這個 key function 再比大小。

也就是說當 list 排好後的元素是 x, y, z,我希望他符合 f(x) < f(y) < f(z),而不是 x < y < z。

以下我定義一個 function f(x),他會讀進一個 tuple x,然後回傳 x 的第二項。這時 sorted 就會按照第二項來做排序。

In [13]: def f(x):
    ...:     return x[1]
    ...: 

In [14]: sorted(score, key=f)
Out[14]: [('rilak', 59), ('hortune', 87), ('melody', 100)]

更多範例

假設 score 變數存放的是三次考試的成績,我們希望按照成績的總和排序。

In [15]: score = [(10, 20, 30), (0, 60, 80), (100, 100, 100)]

In [16]: def f(x):
    ...:     return sum(x)
    ...: 

In [17]: sorted(score)
Out[17]: [(0, 60, 80), (10, 20, 30), (100, 100, 100)]

按照姓名長度排序

In [19]: def f(x):
    ...:     return len(x[0])
    ...: 

In [23]: sorted(score, key=f)
Out[23]: [('rilak', 59), ('melody', 100), ('hortune', 87)]

lambda

如果你覺得「這個 function 這麼廢了吧,還要特別定義出來?」,那你可以使用 lambda 函式:

lambda x:x[1]

def f(x):
    return x[1]

是等價的!只是 lambda 函式沒有名字。我們直接把 lambda 當作 key function 丟進去就行了。

In [24]: sorted(score, key=lambda x:x[1])
Out[24]: [('rilak', 59), ('hortune', 87), ('melody', 100)]

reverse

sort 內的參數有兩個:key 跟 reverse。透過在參數內將 reverse 設定成 True,排序的結果就會顛倒過來:

In [25]: sorted(score, key=lambda x:x[1], reverse=True)
Out[25]: [('melody', 100), ('hortune', 87), ('rilak', 59)]

results matching ""

    No results matching ""