1. 程式人生 > >內建函式 lambda sorted filter map 遞迴

內建函式 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("存在")