1. 遞歸函數
1.1 什么是遞歸?
生活中用到的遞歸:
從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!講的什么呢? 講的是:"從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!講的什么呢? 講的是:'從前有座山,山里有座廟,廟里有個老和尚,正在給小和尚講故事呢!講的什么呢?
遞歸就是函數在運行過程中,直接或者間接的調用了自身。
遞歸的核心:
- 遞推
一層層往下推導答案(每次遞歸之后復制度相較於上一次一定要有所下降) - 回溯
依據最后的結論往后推導出最初需要的答案
重點: 遞歸一定要有結束條件!!!
如果沒有結果條件會一直遞歸下去,python
解釋器中默認遞歸次數是1000
次
>>> import sys
>>> sys.getrecursionlimit()
1000
1.2 遞歸示例
示例1:求第5個人的的年齡,已知第1個人的年齡為18,第2個人比第1個人大兩歲,第3個人比第2個人大兩歲,依次類推
# 代碼:
def foo(num):
if num == 1:
return 18
return foo(num-1) +2
res = foo(5)
print(res)
執行結果:
26
示例2: 只打印列表中的數字
l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,]]]]]]]]]]]]]]
def boo(l):
for i in l:
if type(i) == int:
print(i, end=' ')
else:
boo(i)
boo(l)
print()
執行結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
示例3: 階乘
# 代碼:
def func1(num):
if num == 1:
return 1
return func1(num -1) * num
res = func1(5)
print(res)
# 執行結果:
120
2. 三元表達式
判斷兩個數的大小,返回大的數:
之前的代碼:
# 代碼
def foo(a, b):
if a > b:
return a
else:
return b
print(foo(5, 6))
# 執行結果:
6
使用三元表達式:
def foo2(a,b):
return a if a >b else b
print(foo2(5,6))
# 執行結果:
6
# 判斷用戶輸入的是y或n
user_input=input("Please input y/n:").strip()
Please input y/n:y
if user_input == 'y':
print("OK")
else:
print("NO")
OK
# 使用三元表達式:
>>> user_input=input("Please input y/n:").strip()
Please input y/n:y
>>> "OK" if user_input=='y' else "NO"
'OK'
值 if 條件 else 值
條件成立采用if前面的值,不成立采用else后面的值。
三元表達式還可以嵌套:
>>> res = True if 5 > 4 else (False if 1 < 2 else True)
>>> print(res)
True
# 如果 前面的if 5 > 4為真則直接返回,否則再去計算 else后面的(False if 1 < 2 else True)
>>> res = True if 5 < 4 else (False if 1 < 2 else True)
>>> print(res)
False
但是,三元表達式盡量不要嵌套使用
注意: 當功能需求僅僅是二選一的情況下,那么推薦使用三元表達式
3. 列表生成式
列表生成式:功能是提供一種方便的列表創建方法.
示例1: 給一個列表里面的每一個元素都加個ex_
前綴。
# 給列表每個元素都個ex_前綴,組成一個新列表:
list1 = ['apple', 'orange', 'purple']
new_list = ['ex_apple', 'ex_orange', 'ex_purple']
# 目前代碼實現
# 代碼:
list1 = ['apple', 'orange', 'purple']
new_list=[]
def foo(list1):
for name in list1:
new_list.append("ex_%s" % name)
foo(list1)
print(new_list)
# 執行結果:
['ex_apple', 'ex_orange', 'ex_purple']
# 使用列表生成式
>>> res = ["ex_%s" % name for name in list1]
>>> res
['ex_apple', 'ex_orange', 'ex_purple']
列表生成式里面還可以使用if
# 除了orange外其他元素加`ex_`前綴並加入列表。
>>> res = ["ex_%s" % name for name in list1 if name != 'orange']
>>> res
['ex_apple', 'ex_purple']
# 但 if 后面不能再加else了。
4. 字典生成式
快速生成一個字典。
如果快速把列表 list1 = ['apple', 'orange', 'purple'] 生成一個字典
>>> {i:j for i, j in enumerate(list1)}
{0: 'apple', 1: 'orange', 2: 'purple'}
# enumerate() 為枚舉
# 對於一個可迭代的(iterable)/可遍歷的對象(如列表、字符串),enumerate將其組成一個索引序列,利用它可以同時獲得索引和值。默認從0開始,但可以修改。
>>> {i:j for i, j in enumerate(list1,start=1)}
{1: 'apple', 2: 'orange', 3: 'purple'}
還可以快速生成一個集合:
把 list1 = ['apple', 'orange', 'purple'] 生成一個集合
>>> {i for i in list1}
{'purple', 'apple', 'orange'}
5. 匿名函數lambda
5.1 匿名函數定義和格式
匿名函數:沒有名字的函數.
格式:
lambda 形參:返回值
def foo(n):
return n**2
#就相當於:
lambda n:n**2
# 在調用的時候
>>> print(foo(3))
9
# 而匿名函數:
>>> print((lambda n:n**2)(3))
9
匿名函數一般不會單獨使用 都是配合其他函數一起使用
5.2 和匿名函數結合使用的內置方法
匿名函數一般不會單獨使用 都是配合其他函數一起使用
map() 映射
把列表中 list_num = [1, 2, 3, 4, 5]的元素都乘以2。
正常會把每個元素都遍歷一遍,然后乘以2,最后打印。
還可以使用map()內置方法,它的參數可以是一個函數
def foo(x):
return x*2
print(list(map(foo, list_num)))
[2, 4, 6, 8, 10]
# 還可以把foo替換為一個匿名函數
>>> print(list(map(lambda x:x*2, list_num)))
[2, 4, 6, 8, 10]
面試題:一行代碼打印出來9以內偶數的平方和
>>> sum(map(lambda x:x**2, [x for x in range(1,10) if x % 2 == 0]))
120
zip() 拉鏈
把多個容器中的元素,一一對應組成一上元素
>>> l1 = [1, 2, 3, 4, 5] # 元素個數相等
>>> l2 = ['apple', 'watermelon', 'pear', 'cherry', 'strawberry']
>>> list(zip(l1, l2))
[(1, 'apple'), (2, 'watermelon'), (3, 'pear'), (4, 'cherry'), (5, 'strawberry')]
# 如果兩個列表中元素個數不相等,則以少的元素為准
>>> l1 = [1, 2, 3, 4, 5, 6] # 元素個數不相等
>>> l2 = ['apple', 'watermelon', 'pear', 'cherry', 'strawberry']
# 不但能組合兩個,還可以更多個,但還是以最少元素為准
>>> l1 = [1, 2, 3, 4, 5, 6]
>>> l2 = ['apple', 'watermelon', 'pear', 'cherry', 'strawberry']
>>> l3=('a','b','c','d')
>>> list(zip(l1, l2,l3))
[(1, 'apple', 'a'), (2, 'watermelon', 'b'), (3, 'pear', 'c'), (4, 'cherry', 'd')]
max() 求最大值和min() 求最小值
>>> l1 = [100, 2, 999, 3, 89, 30]
>>> max(l1) # 求最大值
999
>>> min(l1) # 求最小值
2
>>> dict_list = {'Amy':9999,
'Bill': 1999,
'jack':100}
# 打印出數字最大的用戶
# 如果直接使用
>>> max(dict_list)
'jack'
# 發現結果不對,因為dict_list是字典,它只會取key,key為字符串,它會按它的ASCII碼做比較
max用法:
max(iterable, *[, default=obj, key=func]) -> value
max(arg1, arg2, *args, *[, key=func]) -> value
# 可以把字典中的value取出來,然后用max()返回最大值
>>> max(dict_list, key=lambda key:dict_list[key])
'Amy'
# 同理也可以取最小值
>>> min(dict_list, key=lambda x:dict_list[x])
'jack'
# 取出列表元素中值最大的元素
>>> list_num = [['a',5], ['b', 10], ['c', 6]]
>>> max(list_num, key=lambda x:x[1])
['b', 10]
filter() 過濾
filter(function or None, iterable) --> filter object
# 取出列表元素中大於20的元素
>>> list_num = [10, 18, 25, 20, 22]
>>> list(filter(lambda x:x>20, list_num))
[25, 22]
# 取出字典中value大於2000的key
>>> dict_list={'Amy': 9999, 'Bill': 1999, 'jack': 100}
>>> list(filter(lambda x:dict_list[x] > 2000, dict_list))
['Amy']
reduce() 歸總
# 對參數序列中元素進行累積
# 函數將一個數據集合(鏈表,元組等)中的所有數據進行下列操作:用傳給 reduce 中的函數 function(有兩個參數)先對集合中的第 1、2 個元素進行操作,得到的結果再與第三個數據用 function 函數運算,最后得到一個結果。
# 使用的方法:
reduce(function, sequence[, initial]) -> value
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5)
# 在python2中可以直接使用reduce
# 在python3中reduce放到functools模塊中了,使用的話要先從functools中導入
# python2:
>>> reduce(lambda x,y:x+y, [1, 2, 3, 4, 5])
15
>>> reduce(lambda x,y:x*y, [1, 2, 3, 4, 5])
120
# python3
>>> from functools import reduce
>>> list_num = [10, 18, 25, 20, 22]
>>> reduce(lambda x,y:x+y, list_num)
95
>>> reduce(lambda x,y:x*y, list_num)
1980000
# 還可以額外添加元素值
>>> reduce(lambda x,y:x+y, [1, 2, 3, 4, 5], 10)
25
# 10不在原來序列內,為額外添加的
sorted() 排序
# 排序並返回一個新列表
>>> list_num = [10, 18, 25, 20, 22]
>>> sorted(list_num) # 不改變原列表
[10, 18, 20, 22, 25]
# 把下面的字典按value的數值從小到大排序
>>> dict_list = {'Amy': 99, 'Bill': 200, 'jack': 100, 'az':300}
>>> sorted(dict_list,key=lambda x:dict_list[x])
['Amy', 'jack', 'Bill', 'az']
注意:
在python3
中map、filter、zip
返回的是一個迭代器。
在python2
中:
map 返回列表
zip 返回元組列表
filter 返回 列表,元組或字符串
6. 二分法
算法就是解決問題的高效方法。
示例:從一個列表中查找一個數是否存在
# 普通方法,在全部遍歷,然后判斷是否有要找到的值
>>> list_num = [12, 34, 54, 78, 101, 132, 136, 248, 567, 901, 1000]
>>> count=0
>>> for n in list_num:
count+=1
if n == 132:
print("找了%d次,終於找到了" % count)
break
找了6次,終於找到了
# 使用二分法(把元素一分為二)
list_num = [12, 34, 54, 78, 101, 132, 136, 248, 567, 901, 1000]
find_num = 901 # 要找的數
def two(list_num):
num = len(list_num) // 2 # 把元素一分為二
if find_num >list_num[num]: # 如果要找的數,大於中間的數則向右邊找
right_list=list_num[num+1:]
print(right_list)
two(right_list)
elif find_num < list_num[num]: # 如果要找的數,小於中間的數則向左邊找
left_list=list_num[:num]
print(left_list)
two(left_list)
elif find_num == list_num[num]: # 如果正好等於則直接找到了。
print("Good,Find")
else: # 否則就是沒找到
print("Not found")
two(list_num)
# 執行結果:
[136, 248, 567, 901, 1000]
[901, 1000]
[901]
Good,Find
注意 使用二分法,數據必須有序。
如果要查找的元素在開頭 那么還沒有依次遍歷查找的效率高