你會在程式裡面寫函數嗎?
通常寫函數的第一個問題,就是要給函數取名字。
名字取得不好,後來調用函數不自然,就會拖垮整個寫程式的效率。
為函數命名,也是一門技術,好的函數命名,就能提高函數被重複使用的頻率。
然而,也是在某些情況下,我們需要「一次性函數」。
沒錯,用完即丟的函數。
這時候就需要Lambda。
▋1. lambda是一種回傳數據特定形式的匿名函數。
▋2. 定義一個lambda需要指定參數(Parameters)與表達(Expression)
▋3. lambda的關鍵用法,是在將一個函數作為參數輸入另一個函數,也就是執行泛函操作
而這是我理解這3個方面的方式:
lambda 是所謂的「匿名函數 (Anonymous Function)」。
根據維基百科,「匿名函數」是一種不需要與識別符(Identifier)作綁定(Bound)的函數。^[an anonymous function (function literal, lambda abstraction, lambda function, lambda expression or block) is a function definition that is not bound to an identifier.]
這裡的識別符,就是函數的名字;而綁定就是將函數匹配到名字的字串上。
透過 lambda,我們可以省下命名一個函數的工,然後把lambda運算完的結果,儲存到另一個變數中。
這樣的過程十分管用,尤其是在想要對向量或者字典做高階函數運算的時候。
map
來對列表的每一個元素進行平方運算。要將每個元素平方,但其實不用再額外寫一個「平方函數」,透過lambda,直接用map
就可以作用。
squared = map(lambda x: x**2, [1, 2, 3, 4])
print(list(squared)) # 輸出會是 [1, 4, 9, 16]
filter
來過濾出列表中大於 10 的元素。要比大小,直觀事先對每個元素比大小,把比大小結果的1與0翻譯回來。但透過lambda,可以省去for迴圈以及比大小的過程。
filtered = filter(lambda x: x > 10, [5, 11, 3, 12])
print(list(filtered)) # 輸出會是 [11, 12]
sorted
來依照特定規則排序一個元組列表。要給元組排序是一件苦差事,你要先指定維度,然後在一個一個去比。但透過lambda,可以直接搭配sorted
來拿到結果,不用額外寫一個函數去一個一個比。
pairs = [(1, 'one'), (4, 'four'), (3, 'three'), (2, 'two')]
sorted_pairs = sorted(pairs, key=lambda x: x[1])
print(sorted_pairs) # 輸出會是 [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
原則上,掌握lambda,你可以寫出更簡潔的Python code,也可以提高可用性。lambda尤其是在處理trivial的運算特別好用!
要創造lambda,其語法是
lambda parameters:expression
其中
會寫lambda非常有用,可以客製化很多簡單的運算。
例子一:乘法
multiply = lambda x, y: x * y
print(multiply(5, 3)) # Output: 15
例子二:最大值
maximum = lambda x, y: x if x > y else y
print(maximum(5, 8)) # Output: 8
例子三:反轉布林值
negate = lambda x: not x
print(negate(True)) # Output: False
print(negate(False)) # Output: True
例子四:字符串拼接
concatenate = lambda str1, str2: str1 + str2
print(concatenate("Hello, ", "world!")) # Output: Hello, world!
例子五:串連三個字串的第一個元素
concat_strings = lambda a, b, c: a[0] + b[0] + c[0]
print(concat_strings("World", "Wide", "Web"))
例子六:拿列表的第一個元素
first_element = lambda x: x[0] if len(x) > 0 else "List is empty"
print(first_element([1, 2, 3])) # Output: 1
print(first_element([])) # Output: List is empty
妥善去使用lambda,甚至可以把程式代碼變得更加口語化,讓各種抽象的操作變得更加簡潔,非常值得學習。
泛函(Functional)是一種以「函數」為定義域的映射。
也就是說,每一個泛函要運算時,都要輸入一個函數作為參數,然後輸出我們需要的資訊。
舉一個統計中常見的例子,是計算「樣本變異 (Sample Variance)」。
將計算樣本變異看為泛函操作,那所需要輸入的函數其實是「取平均後開根號」,因為樣本變異是平均數(平均值)周圍數據點變動的一種度量。簡單來說,樣本變異是數據點與平均值的差值平方的平均。在這個情境下,"取平均後開根號" 的函數可以被看作是一個泛函的參數。
如果將這個操作使用 Python 來實現,我們可以用 lambda 函數來表達:
# 一個簡單的平均數函數
average = lambda arr: sum(arr) / len(arr)
# 樣本變異的泛函
def sample_variance_functional(f, data):
mean = f(data) # 使用輸入的函數計算平均數
return sum((x - mean)**2 for x in data) / (len(data) - 1)
# 使用泛函計算樣本變異
data = [1, 2, 3, 4, 5]
result = sample_variance_functional(average, data)
print("Sample Variance:", result)
在這個例子中,sample_variance_functional
是一個泛函,它接受一個函數 f
和一個數據集 data
,然後計算該數據集的樣本變異。這個泛函使用了輸入的函數 f
(在這裡是 average
)來計算數據集的平均數,然後用這個平均數去計算樣本變異。
這個例子展示了 lambda 函數和泛函的概念是如何結合在一起的。通過這種方式,我們可以將各種不同的函數(比如加權平均,中位數等)作為 sample_variance_functional
的參數,來計算相對應的樣本變異。
這提供了高度的靈活性和可擴展性。我們可以把輸入的函數f
替換成其他的函數,可以是weighted_average
或者是其他形式的平均,如此來討論更廣義的「變異數 (Variance)」觀念。
假設我們有一個數組,我們想對這個數組的每一個元素取平方根。我們可以定義一個泛函,這個泛函接受一個函數(這裡是取平方根的函數)和一個數組,然後返回一個新的數組。
import math
# 定義一個泛函,這個泛函接受一個函數 f 和一個列表 lst
def map_functional(f, lst):
return list(map(f, lst))
# 使用 lambda 函數定義取平方根的操作
sqrt_function = lambda x: math.sqrt(x)
# 定義一個數組
numbers = [1, 4, 9, 16, 25]
# 使用泛函計算數組的平方根
sqrt_numbers = map_functional(sqrt_function, numbers)
print("Square roots:", sqrt_numbers)
在這個例子中,map_functional
是一個泛函,它接受一個函數 f
和一個列表 lst
。這個泛函用 map
函數來對列表 lst
的每一個元素應用函數 f
,然後返回一個新的列表。
這樣,我們就可以使用不同的函數(不只是取平方根)來轉換 numbers
列表。這提供了高度的靈活性,允許我們輕鬆地替換處理數據的邏輯。
我們可以使用 filter
和 lambda
函數來過濾一個列表中的元素。這裡的例子是一個泛函,它接受一個判斷函數(predicate function)和一個列表,然後返回一個只包含符合條件的元素的新列表。
# 定義一個泛函,這個泛函接受一個函數 f 和一個列表 lst
def filter_functional(f, lst):
return list(filter(f, lst))
# 使用 lambda 函數定義一個判斷是否為偶數的函數
is_even = lambda x: x % 2 == 0
# 定義一個整數列表
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 使用泛函過濾出偶數
even_numbers = filter_functional(is_even, numbers)
print("Even numbers:", even_numbers)
在這個例子中,filter_functional
是一個泛函,它接受一個函數 f
和一個列表 lst
。然後它用 filter
函數來過濾出列表 lst
中符合函數 f
條件的元素。
這樣,我們就可以使用不同的判斷函數來過濾 numbers
列表,這提供了很高的靈活性。例如,我們可以簡單地更換 lambda 函數,以過濾出大於 5 的所有數字,或者能被 3 整除的數字等等。
如此,只要能活用lambda,搭配上泛函的框架,就能操作各式各樣稍微複雜的數學操作!掌握lambda思維,就能掌握計算數學的能力!
學習如何正確地使用 lambda 函數和泛函是一個值得投資的時間和努力的過程。他們不僅可以幫助你寫出更簡潔、更高效的程式碼,而且也能提供更高的靈活性和可擴展性。
通過這篇文章,我們探討了以下三個方面:
透過實例和代碼,你也看到了這些與lambda相關的概念是如何具體應用的。希望這能幫助你更好地理解和使用 lambda 函數,並在你的程式設計之旅中找到它們的價值!