內建函式 lambda sorted filter map 遞迴
一 lambda 匿名函式
為了解決一些簡單的需求而設計的一句話函式
# 計算 n 的 n次方 def func(n): return n**n print(func(10)) f = lambda n:n**n print(f(10))
lambda 表示的是 匿名函式,不需要用 def 宣告,一句話就可以宣告出一個函式
語法:
l函式名 = lambda 引數:返回值
注意:
1.返回值可以是一個,也可以是多個,多個 的時候用 逗號 隔開 在 元祖 () 裡邊
2.lambda 不管多複雜 只能寫 一行 , 執行完畢 返回資料
3.lambda 和正常 函式一樣 ,返回值 可以 是 任意 資料型別
匿名函式並不是說一定沒有名字. 這里前面的變數就是一個函式名. 說他是匿名原因是我們通
過__name__檢視的時候是沒有名字的. 統一都叫lambda. 在呼叫的時候沒有什麼特別之處.像正常的函式呼叫即可
二 sorted 排序函式
語法:
sorted(iterable,key = None,reverse=False)
iterable :可迭代物件
key = 排序規則(排序函式) 在 sorted 內部 會將 可迭代物件中的 每一個 元素傳遞給 這個函式的引數
根據 函式運算的 結果進行 排序
reverse; 是否是 倒序 True 倒序 False 正序
lst = [1,5,8,9,2,6,4,3,7] lst1 = sorted(lst) print(lst) # [1, 5, 8, 9, 2, 6, 4, 3, 7] 原列表不變print(lst1) # [1, 2, 3, 4, 5, 6, 7, 8, 9] 返回的列表是經過排序的 dic = {1:"a",3:"b",2:"c"} dic1 = sorted(dic) print(dic) # {1: 'a', 3: 'b', 2: 'c'} print(dic1) # [1, 2, 3] 如果是字典,返回經過排序的 key
# 和 函式 組合使用 lst = ["張曼玉","邱淑貞","朱茵","你","上官寒冰"] def func(s): return len(s) print(sorted(lst,key=func)) # ['你', '朱茵', '張曼玉', '邱淑貞', '上官寒冰'] # 和 lambda 組合使用 lst = ["張曼玉","邱淑貞","朱茵","你","上官寒冰"] lst1 = (sorted(lst,key = lambda s:len(s))) print(lst1) # ['你', '朱茵', '張曼玉', '邱淑貞', '上官寒冰']
lst = [{"id":1, "name":'alex', "age":18},
{"id":2, "name":'wusir', "age":16},
{"id":3, "name":'taibai', "age":17}]
# 按照年齡對學生進行排序
func = sorted(lst,key=lambda dic:dic["age"])
print(func)
三 filter() 篩選函式
語法:
filter(function,iterable)
function:用來篩選的函式,在 filter 中 會自動的吧 iterable 中的 元素傳遞個i function,然後根據 function返回
的 True 或者 False 來判斷是否保留 此項資料
iterable : 可迭代物件
#篩選所有的 偶數 lst = [1,2,3,4,5,6,7,8,9] l = filter(lambda x:x % 2 == 0,lst) print(l) # <filter object at 0x013E7690> print(list(l)) # [2, 4, 6, 8] lst = [{"id":1, "name":'alex', "age":18}, {"id":2, "name":'wusir', "age":16}, {"id":3, "name":'taibai', "age":17}] # 篩選年齡大於 16 的資料 lst1 = filter(lambda dic:dic["age"]>16,lst) print(list(lst1)) # [{'id': 1, 'name': 'alex', 'age': 18}, {'id': 3, 'name': 'taibai', 'age': 17}]
四 map() 對映函式
語法:
map(function,iterable) 可以對 可迭代物件中的 每一個 元素 進行對映 ,分別取執行 function
# 計算列表中 每個元素的 平方,返回新列表 # 1.和函式 組合 使用 def func(s): return s**2 mp = map(func ,[1,2,3,4]) print(mp) ## <map object at 0x013F7710> print(list(mp)) ## [1, 4, 9, 16] # 2.和 lambda 組合 使用 print(list(map(lambda i:i**2,[1,2,3,4]))) # [1,4,9,16] # 計算兩個 列表中 相同 位置的資料的 和 lst = [1,2,3,4,5] lst1 = [5,4,3,2,1] print(list(map(lambda x,y:x+y,lst,lst1))) # [6, 6, 6, 6, 6]
五 reduce() 通過某個函式,累計按順序計算列表中的值 可以 算 累加 累乘 等等吧
python2.x 中 直接 import reduce
python3.x 中 from functools import reduce
from functools import reduce def func(x,y): return x + y # reduce 的使用方法 # reduce(函式名,可迭代物件) # 這兩個引數必須都要有,缺一個不行 ret = reduce(func,[3,4,5,6]) print(ret) reduce 的作用是 先把列表中的 前兩個元素取出計算一和值,然後臨時儲存 接下來用這個零時儲存的值 和 列表中的下一個 再計算,以此類推 # 注意 我們放進去的可迭代物件沒有 更改
from functools import reduce # 匯入reduce 模組 # 和 lambda 組合 使用 print(reduce(lambda x,y:x*y,[1,2,3,4])) # 24
六 zip() 拉鍊函式
zip(*iterables) 生成一個 迭代器(迭代器本質是 生成器),它聚合了 可迭代物件的 每個元素
返回 一個 由 元祖組成的 迭代器,其中 第 i 個元祖 包含 來自每個引數序列 或 可迭代物件的 第i個元素,
當最短的 可迭代物件被 輸出時,該 迭代器完成
# 原理如下 def zip(*iterables): # zip("ABCD","xy") ---> Ax By sentinel = object() itetators = [iter(it) for it in iterables] while itetators: result = [] for it in itetators: elem = next(it,sentinel) if elem is sentinel: return result.append(elem) yield tuple(result) f = zip([1,2,3],[4,5,6,7]) print(f.__next__()) # (1,) print(f.__next__()) # (1, 4) print(f.__next__()) # (2,) print(f.__next__()) # (2, 5)
x = [1,2,3,4]
y = ["張曼玉","邱淑貞","張敏"]
z = [11,22,33,44,55]
print(list(zip(x,y,z)))
# [(1, '張曼玉', 11), (2, '邱淑貞', 22), (3, '張敏', 33)]
print(list(zip(*zip(x,y,z))))
# [(1, 2, 3), ('張曼玉', '邱淑貞', '張敏'), (11, 22, 33)]
# * 的作用是把上面生成的 迭代器 又 再次 拉鍊式的 組合了該 迭代器中的 元素
lst = [1,2,3,4,5,6] lst1 = ["anglobay","haha","hahag","張敏","邱淑貞"] tu = ("**","***","****","******") b = filter(lambda x:x[0] > 2 and len(x[2]) > 4,zip(lst,lst1,tu)) print(list(b)) # [(4, '張敏', '******')]
七 遞迴函式 在函式中呼叫函式本身,就是遞迴
遞迴是什麼
在數學和電腦科學中,遞迴指由一種(或多種)簡單的基本情況定義的一類物件或方法,
並規定其他所有情況都能被還原為其基本情況。
遞迴的三要素
- 一個問題的解可以分解為幾個子問題的解
- 這個問題與分解之後的子問題,除了資料規模不同,求解思路完全一樣
- 一定存在終止遞迴的條件
關鍵點
- 寫出遞推公式
- 找到終止條件
- 將遞推公式轉化為程式碼
遞迴程式碼要警惕堆疊溢位
函式呼叫會使用棧來儲存臨時變數,每呼叫一個函式,都會將臨時變數封裝為棧幀壓入記憶體棧,等函式執行完成返回時,才出棧。系統棧或者虛擬機器棧空間一般都不大,如果遞迴求解的資料規模很大,呼叫層次很深,一直壓入棧,就會有堆疊溢位的風險。
如何避免堆疊溢位?
- 在程式碼中限制遞迴呼叫的最大深度,當遞迴呼叫超過一定深度,比如1000之後,就不再繼續往下遞迴了,直接返回報錯。但是如果遞迴深度比較大,這種方法就不太適用。
- 採取迴圈的方式來解決,將需要的資料在關鍵的呼叫點儲存下來使用。簡單的說,就是用自己的資料儲存方法來代替系統遞迴呼叫產生的堆疊資料。
遞迴程式碼要警惕重複計算
使用遞迴的時候,還會出現重複計算的問題。為避免重複計算,我們可以通過一個數據結構(比如散列表)來儲存已經求解過的遞迴函式值 f(k),當遞迴呼叫到 f(k) 時,先看下是否已經求解過了,如果是,則直接從散列表中取值返回,不需要重複計算,這樣就能避免重複計算了。
內容小結
- 遞迴是一種非常高效、簡潔的程式設計技巧。
- 只要是滿足“遞迴三要素”的問題,就可以通過遞迴程式碼來解決。
- 編寫遞迴程式碼的關鍵點在於:寫出遞推公式,找出終止條件,然後再翻譯成遞迴程式碼。
- 遞迴程式碼雖然簡潔高效,但是也存在很多弊端,如:堆疊溢位、重複計算、函式呼叫耗時多、空間複雜度高等等,在使用遞迴時,一定要控制好這些副作用。
def func(): print("我是func") func() fucn() # 在python 中,官方解釋 遞迴最大深度1000,但是永遠不會跑到1000 # 我實測 998 # 怎麼測的 呢?? 其實很簡單,就是利用累加 def func(n): print(n) n += 1 func(n) func(1)
遞迴的應用:
我們可以使用遞迴來遍歷各種樹形 結構,比如我們的資料夾系統
# 引入os 模組 import os def func(filepath,n): files = os.listdir(filepath) # 獲取到當前資料夾的所有檔案 for fi in files: # 遍歷資料夾中的 內容,這裡獲取到的是本層檔名 fi_d = os.path.join(filepath,fi) # 加入資料夾,獲取到資料夾 + 檔案 if os.path.isdir(fi_d): # 如果該路徑下的是資料夾 print("\t"*n,fi) # 打印出檔名 func(fi_d,n +1) # 繼續進行相同的 操作 else: print("\t" * n, fi) # 遞迴出口,最終在這裡隱含著 return # 遞迴 遍歷 d盤目錄下 所有檔案 func("d:/learn-py",0)
八 二分查詢
每次查詢能夠排除掉一半 的資料,查詢的效率 非常高,但是侷限性比較大,必須是有序序列才可以用二分法
要求: 查詢的序列 必須是 有序序列
# 二分查詢 ---- 非遞迴演算法 lst = [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,100,101,111,222,333] num = int(input("輸入你要查詢的數字:")) left = 0 right = len(lst) - 1 count = 1 while left <= right: middle = (left + right) // 2 if num > lst[middle]: left = middle + 1 elif num < lst[middle]: right = middle - 1 else: print(count) print(middle) count += 1 else: print("不存在")
# 普通 遞迴版本 二分法
# 利用 索引切片,切了列表,不符合的 切掉
# 當 列表 切完了之後,就可以判斷了
# 很難計算 位置
lst = [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,100,101,111,222,333] num = int(input("輸入你要查詢的數字:")) def func(n,lst): left = 0 right = len(lst) - 1 if lst != []: middle = (left + right) // 2 if num > lst[middle]: func(n,lst[middle + 1:]) elif num < lst[middle]: func(n,lst[:middle]) else: print("找到了") return None else: print("沒找到") return None print(func(num,lst))
# 判斷 num 是不是在 列表中,可以返回 num 所在的 位置 # 用 遞迴,要找到設麼是 可變的,什麼是不可變的 \ # 列表不動 lst = [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,100,101,111,222,333] num = int(input("輸入你要查詢的數:")) def func(n,lst,left,right): if left <= right: middle = (left + right) // 2 if n > lst[middle]: left = middle + 1 return func(n,lst,left,right) elif n < lst[middle]: right = middle - 1 return func(n,lst,left,right) else: print("找到了") return middle else: print("找不到") return -1 ret = func(num,lst,0,len(lst) - 1) print(ret)
# 還有一種查詢方法 # 堪稱最快之 查詢方法 ,此方法 不需要 列表是 有序的 lst = [1,2,55,66,88,3,44,6,5,7,8,111,222,333] new_lst = [] for i in range(334): new_lst.append(i) for el in lst: new_lst[el] = 1 num = int(input("輸入你要查詢的數字:")) if new_lst[num] == 0: print("不存在") else: print("存在")