Python3中sorted()函數
與lambda表達式
原理解析
相信很多小夥伴們在一開始學習Python的一些高級用法時遇到過很多困擾。
我準備日常分享一些比較淺顯的原理解析幫助大家理解。
博主的原文:
問題描述
很多小夥伴面對這樣的排序,很是懵逼:
# 預按照每個字典中鍵'b'的值進行列表排序
L = [{'a': 1, 'b': 4}, {'a': 1111, 'b': 2}, {'a': 1111, 'b': 3}]
L_sorted = sorted(L, key=lambda d: d['b'], reverse=False)
print(L_sorted)
運行結果:
[{'a': 1111, 'b': 2}, {'a': 1111, 'b': 3}, {'a': 1, 'b': 4}]
這裏麪包含了函數高級用法中的sorted和lambda的兩個用法
下面,我將逐一解析。
原理解析
lambda表達式
相當於一個簡化的函數sorted(iterable, key=None, reverse=False)
,此處的key=
需要傳遞一個函數,相當於將iterable
中的每一個元素迭代取出,傳入key=
處給定的函數,通過函數處理返回的值組成的新的迭代對象,通過該新對象的排序映射回iterable
完成排序。
示例1:lambda表達式理解:
# 1) 普通函數func_add的定義
def func_add(x, y):
return x + y
print(func_add(10, 20)) # 30
# 2) 對於函數func_add, 可以使用lambda表達式一行定義
myadd = lambda x, y: x + y
print(myadd(10, 20)) # 30
示例2: sorted函數理解
# sorted原理解析 —— 自定義函數實現sorted
def my_sorted(iters, key=None, reverse=None):
if key:
DICT = dict()
for it in iters:
# 用函數處理過後的值做鍵, 處理相同的鍵加入列表
DICT.setdefault(key(it), []).append(it)
INDEX = list(DICT) # 獲得函數處理過後的值列表
INDEX.sort(reverse=reverse) # 排序
# 按順序展開
return [xx for x in INDEX for xx in DICT[x]]
else:
INDEX = list(iters)
INDEX.sort(reversed=reverse)
return INDEX
names = ['Tom', 'Spike', 'Jerry', 'Tyke']
L = sorted(names, key=len, reverse=True)
print(L) # 結果 ['Tom', 'Tyke', 'Jerry', 'Spike']
L = my_sorted(names, key=len, reverse=True)
print(L) # 結果 ['Tom', 'Tyke', 'Jerry', 'Spike']
附:原文基礎知識
lambda表達式
(原文鏈接: lambda表達式)
引入:
- 除了def語句可以創建函數之外,lambda表達式也可以創建函數。
概念:
- lambda表達式(又稱匿名函數),用於封裝有限的邏輯的函數
- lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
語法格式:
lambda [變量1,變量2,… ]:表達式
說明:
- 可以省略變量
- 只能包含一條表達式
示例:lambda函數理解
# 1) 普通函數func_add的定義
def func_add(x, y):
return x + y
print(func_add(10, 20)) # 30
# 2) 對於函數func_add, 可以使用lambda表達式一行定義
myadd = lambda x, y: x + y
print(myadd(10, 20)) # 30
# 3) 語法理解 x 爲形參接收值, 後面緊跟表達式返回值
myfunc = lambda x: 123 + x
print(myfunc(100)) # 223
# lambda可以行使正常函數的所有功能
myfunc = lambda: print('hello', end=' ')
print(myfunc()) # hello None
# 求1到10的平方和
fun = lambda x: sum([x * x for x in range(1, x + 1)])
print(fun(10)) # 385
sorted 函數
(原文鏈接: sorted()函數)
-
作用:
- 將原可迭代對象提供的數據進行排序,生成排序後的列表
-
格式:
sorted(iterable, key=None, reverse=False)
- 說明:
iterable
可迭代對象key
函數是用來提供一個排序參考值的函數,這個函數的返回值將作爲排序的依據reverse
標誌用來設置是否降序排序
- 返回
- 列表
list
- 列表
-
理解:
- 此處的
key=
需要傳遞一個函數,相當於將iterable
中的每一個元素迭代取出,傳入key=
處給定的函數,通過函數處理返回的值組成的新的迭代對象,通過該新對象的排序映射回iterable
完成排序。
- 此處的
-
與列表中自帶方法
L.sort()
有什麼區別?sorted(L)
- 是Building域名空間的一個系統函數;
- 是將L作爲參數輸入,返回新列表,對原列表無影響;
L.sort()
- 是list類中的一個方法,只能痛毆;
- 是將L的內部元素進行直接排列,不返回新對象
- 示例:
L = [3, 5, 4, 2, 1] L2 = sorted(L) print("L:", L, "L2:", L2) # L: [3, 5, 4, 2, 1] L2: [1, 2, 3, 4, 5] a = L.sort() print("L:", L, "a:", a) # L: [1, 2, 3, 4, 5] a: None
示例1: sorted的簡單示例
L = [5, -2, -4, 0, 3, 1]
print(sorted(L)) # 直接按大小排序
# [-4, -2, 0, 1, 3, 5]
print(sorted(L, key=abs)) # 按絕對值排序
# [0, 1, -2, 3, -4, 5]
print(sorted(L, key=abs, reverse=True) # 按絕對值降序排序
# [5, -4, 3, -2, 1, 0]
示例2: sorted原理解析 —— 自定義函數實現sorted
# sorted原理解析 —— 自定義函數實現sorted
def my_sorted(iters, key=None, reverse=None):
if key:
DICT = dict()
for it in iters:
# 用函數處理過後的值做鍵, 處理相同的鍵加入列表
DICT.setdefault(key(it), []).append(it)
INDEX = list(DICT) # 獲得函數處理過後的值列表
INDEX.sort(reverse=reverse) # 排序
# 按順序展開
return [xx for x in INDEX for xx in DICT[x]]
else:
INDEX = list(iters)
INDEX.sort(reversed=reverse)
return INDEX
names = ['Tom', 'Spike', 'Jerry', 'Tyke']
L = sorted(names, key=len, reverse=True)
print(L) # 結果 ['Tom', 'Tyke', 'Jerry', 'Spike']
L = my_sorted(names, key=len, reverse=True)
print(L) # 結果 ['Tom', 'Tyke', 'Jerry', 'Spike']
高級示例:
lambda
與sorted
高級聯用
- 對列表裏的字典排序
L = [{'a': 1, 'b': 4}, {'a': 1111, 'b': 2}, {'a': 1111, 'b': 3}]
L_sorted = sorted(L, key=lambda d: d['b'], reverse=False)
# [{'a': 1111, 'b': 2}, {'a': 1111, 'b': 3}, {'a': 1, 'b': 4}]
- 對字典進行按key排序
d = {'a':25, 'c':27, 'b':20, 'd':22}
L_sorted = sorted(d.items(), key=lambda x:x[0])
print(L_sorted)
# [('a', 25), ('b', 20), ('c', 27), ('d', 22)]
- 對字典進行按values排序
d = {'a':25, 'c':27, 'b':20, 'd':22}
L_sorted = sorted(d.items(), key=lambda x:x[1])
print(L_sorted)
# [('b', 20), ('d', 22), ('a', 25), ('c', 27)]
- 降序排序的另類寫法
- 問題一:如何對字母進行數學上寫法的降序排序?
- 利用
ord()
函數轉爲編碼值,再*-1
- 利用
Data = [['y', 2], ['x', 3], ['z', 4], ['a',1]]
# 對每個列表的第一個值進行正常排序
print(sorted(Data, key=lambda x: x[0]))
# [['a', 1], ['x', 3], ['y', 2], ['z', 4]]
# 對每個列表的第一個值進行降序排序
print(sorted(Data, key=lambda x: x[0], reverse=True))
# [['z', 4], ['y', 2], ['x', 3], ['a', 1]]
print(sorted(Data, key=lambda x: ord(x[0])*-1)) # 問題一
# [['z', 4], ['y', 2], ['x', 3], ['a', 1]]
# 對每個列表的第二個值進行正常排序
print(sorted(Data, key=lambda x: x[1]))
# [['a', 1], ['y', 2], ['x', 3], ['z', 4]]
# 對每個列表的第二個值進行降序排序
print(sorted(Data, key=lambda x: x[1], reverse=True))
# [['z', 4], ['x', 3], ['y', 2], ['a', 1]]
print(sorted(Data, key=lambda x: x[1]*-1))
# [['z', 4], ['x', 3], ['y', 2], ['a', 1]]
- 多重排序
- 難點:
- 如何實現部分列的升序和部分列的降序排序同時存在?
# - 排序規則
# - 先按照書籍編號降序排序
# - 再按照書名正序排序
# - 再按照年份降序排序
# 書籍的編號
number = {
"Robinson Crusoe": "B",
"The Old Man and the Sea": "A",
"The Little Prince": "C",
"Secret garden": "A",
"Thorn bird": "A"
}
# 年份,書籍,銷售額
data_text = """2017,126,Robinson Crusoe
2017,110,The Old Man and the Sea
2017,152,The Little Prince
2017,98,Secret garden
2017,89,Thorn bird
2018,116,Robinson Crusoe
2018,98,The Old Man and the Sea
2018,176,The Little Prince
2018,79,Secret garden
2018,90,Thorn bird
2019,122,Robinson Crusoe
2019,102,The Old Man and the Sea
2019,187,The Little Prince
2019,102,Secret garden
2019,103,Thorn bird"""
Datas = [x.split(',') for x in data_text.splitlines()]
# 對數據進行排序
result = sorted(Datas, key=lambda x: (ord(number[x[2]])*-1,
x[2], int(x[0])*-1))
# 結果的打印
for x in result:
print(number[x[2]], *x, sep='\t')
運行結果:
C 2019 187 The Little Prince
C 2018 176 The Little Prince
C 2017 152 The Little Prince
B 2019 122 Robinson Crusoe
B 2018 116 Robinson Crusoe
B 2017 126 Robinson Crusoe
A 2019 102 Secret garden
A 2018 79 Secret garden
A 2017 98 Secret garden
A 2019 102 The Old Man and the Sea
A 2018 98 The Old Man and the Sea
A 2017 110 The Old Man and the Sea
A 2019 103 Thorn bird
A 2018 90 Thorn bird
A 2017 89 Thorn bird
- itemgetter與attrgetter模塊的使用
- 可以簡化代碼
from operator import itemgetter
student_tuples = [
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10),
]
# 按照索引爲2的數據排序
print(sorted(student_tuples, key=itemgetter(2)))
# [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
# 多重排序:按照索引爲1,再按照2的數據排序
print(sorted(student_tuples, key=itemgetter(1, 2)))
# [('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
from operator import attrgetter
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
self.age = age
def __repr__(self):
return repr((self.name, self.grade, self.age))
student_objects = [
Student('john', 'A', 15),
Student('jane', 'B', 12),
Student('dave', 'B', 10),
]
# 按age排序
print(sorted(student_objects, key=attrgetter('age')))
# [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
# 多重排序,先以grade,然後再以age來排序
print(sorted(student_objects, key=attrgetter('grade', 'age')))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
練習:
- 已知:
names = ['Tom', 'Jerry', 'Spike', 'Tyke']
- 排序的依據爲原字符串反序的字符串
'moT', 'yrreJ', 'ekipS', 'ekyT'
- 結果:
['Spike', 'Tyke', 'Tom', 'Jerry']
參考:
>>> sorted(['Tom', 'Jerry', 'Spike', 'Tyke'],
key=lambda x:x[::-1])
['Spike', 'Tyke', 'Tom', 'Jerry']