當(dāng)前位置:
首頁 >
c++ map用法_Python专题——五分钟带你了解map、reduce和filter
發(fā)布時間:2025/3/15
36
豆豆
生活随笔
收集整理的這篇文章主要介紹了
c++ map用法_Python专题——五分钟带你了解map、reduce和filter
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
點擊上方藍字,和我一起學(xué)技術(shù)。今天是Python專題第6篇文章,給大家介紹的是Python當(dāng)中三個非常神奇的方法:map、reduce和filter。不知道大家看到map和reduce的時候有沒有什么感覺,如果看過之前我們大數(shù)據(jù)系列介紹MapReduce文章的同學(xué),想必有些印象。這個MapReduce不是一個分布式的計算方法么,怎么又變成Python中的方法了?其實原因很簡單,因為Python是一門很年輕的語言,它在發(fā)展的過程當(dāng)中吸收了很多其他領(lǐng)域的精華,MapReduce就是其中之一。對之前文章感興趣的同學(xué)可以點擊下方的鏈接,回顧一下之前MapReduce的內(nèi)容。
print(dis(point))但是有了map之后, 我們可以省去循環(huán)的操作,整個代碼簡化成了一行:map(dis, points)但是要注意,我們調(diào)用完map之后得到的結(jié)果不是一個list而是一個迭代器。我們直接將map返回的內(nèi)容print出來,可以得到這樣一個結(jié)果:>>> print(map(dis, points))0x107aad1d0>這是一個類的標準輸出,其實它返回的不是最后的結(jié)果,而是一個迭代器。我們在之前的文章當(dāng)中已經(jīng)介紹過了迭代器和生成器的相關(guān)概念,這里不多做贅述了,遺忘的同學(xué)可以點擊下方鏈接回顧一下之前的內(nèi)容:
[1.0, 4.47213595499958, 3.605551275463989]以上過程還可以進一步簡化,還記得我們之前介紹過的匿名函數(shù)嗎?由于dis函數(shù)在我們的程序當(dāng)中只會在map中用到,我們完全沒有必要單獨創(chuàng)建一個函數(shù),我們可以直接傳入一個匿名函數(shù)搞定運算:map(lambda x: math.sqrt(x[0]**2 + x[1] ** 2), points)簡單總結(jié)一下,map操作其實執(zhí)行的是一個映射。它可以自動地將一個序列當(dāng)中的內(nèi)容通過制定的函數(shù)映射成另一個序列,從而避免顯式地使用循環(huán)來調(diào)用,在很多場景下可以大大地簡化代碼的編寫,可以很方便地將一個序列整體轉(zhuǎn)變成另一個結(jié)果。
print(reduce(f, [1, 2, 3, 4]))最終得到的結(jié)果當(dāng)然是10,同樣,我們也可以將reduce中的方法定義成匿名函數(shù),一樣不影響最終的結(jié)果。print(reduce(lambda x, y: x + y, [1, 2, 3, 4]))
texts = ['apple bear peach grape', 'grape orange pear']# 第一次map,將字符串轉(zhuǎn)成數(shù)組,每個單詞對應(yīng)1def mp1(text):
ret = []
words = text.split(' ')for word in words:
ret.append((word, 1))return ret# 第二次map,將數(shù)組轉(zhuǎn)成dictdef mp2(arr):
d = defaultdict(int)for k, v in arr:
d[k] += vreturn d# reduce,合并dictdef rd(x, y):
x.update(y)return x
print(reduce(rd, map(mp2, map(mp1, texts))))那如果我們不用多次MapReduce呢?也不是沒有辦法,需要取點巧,方法也簡單只要使用之前我們講解過的Counter類,就可以完美解決這個問題。我們來看代碼:from collections import Counter
texts = ['apple bear peach grape', 'grape orange pear']def mp(text):
words = text.split(' ')return Counter(words)
print(reduce(lambda x, y: x + y, map(mp, texts)))由于我們使用了Counter,所以我們在map階段返回的結(jié)果就已經(jīng)是詞頻的dict了,而在reduce階段我們只需要將它們?nèi)坷奂悠饋砭蚈K了。最后,我們來看下filter。
[i for i in arr if i % 2 > 0 ]而使用filter會非常方便:list(filter(lambda x: x % 2 > 0, arr))從這個例子當(dāng)中可能看不出便捷,但是有的時候判斷的條件可能非常復(fù)雜,我們判斷的邏輯不能簡單地在list定義當(dāng)中表達出來,這個時候使用filter則會容易得多。最后, 我們再看一個類似的用法。在itertools當(dāng)中有一個方法叫做 compress,通過compress我們可以實現(xiàn)根據(jù)一個序列的條件過濾另一個序列。舉個簡單的例子,假設(shè),我們有兩個數(shù)組:student = ['xiaoming', 'xiaohong', 'xiaoli', 'emily']
scores = [60, 70, 80, 40]我們想要獲取所有考試及格的同學(xué)的list,如果用常規(guī)做法基本上免不了使用循環(huán),但是使用compress可以很方便地通過一行代碼實現(xiàn):from itemtools import compress>>> pass = [i > 60 for i in scores]>>> print(pass)
[False, True, True, False]>>> list(compress(student, pass))
['xiaohong', 'xiaoli']需要注意的是filter和compress返回的都是一個迭代器,我們要獲取它們的值,需要手動轉(zhuǎn)換成list。雖然在日常的開發(fā)當(dāng)中不使用這三樣神器同樣可以工作,但是用上它們之后,會提升很多代碼的可讀性,節(jié)省很多無用的代碼。尤其是在面試的時候,很有可能就會給面試官留下不一樣的印象,也許結(jié)果也會不同。今天的文章就是這些,如果覺得有所收獲,請順手點個在看或者轉(zhuǎn)發(fā)吧,你們的舉手之勞對我來說很重要。
大數(shù)據(jù)基石——Hadoop與MapReduce
map
map除了地圖之外,另一個英文本意是映射。在C++和Java一些語言當(dāng)中,將map進一步引申成了存儲key和value映射結(jié)構(gòu)的容器。Python對這點做了區(qū)分,KV結(jié)構(gòu)的容器命名成了dict,即字典,而map則回到了它的本意,也就是映射。我們都知道,在數(shù)學(xué)領(lǐng)域,映射也是函數(shù)的定義。一個自變量通過某種映射,對應(yīng)到一個因變量。同樣,在Python當(dāng)中,map操作本質(zhì)也是函數(shù),不過它作用的范圍不再是單個變量,而是一個序列。換句話說,通過map我們可以省去循環(huán)操作,可以自動將一個容器當(dāng)中的元素套用一個函數(shù)。舉個簡單的例子,比如我們有一個坐標,我們希望知道它距離原點的距離。這個問題很簡單,我們寫一個計算距離的函數(shù)就可以解決:def dis(point):return math.sqrt(point[0]**2 + point[1]**2)那如果我有多個點需要計算距離,在map出現(xiàn)之前,我們只能用循環(huán)來解決問題:points = [[0, 1], [2, 4], [3, 2]]for point in points:print(dis(point))但是有了map之后, 我們可以省去循環(huán)的操作,整個代碼簡化成了一行:map(dis, points)但是要注意,我們調(diào)用完map之后得到的結(jié)果不是一個list而是一個迭代器。我們直接將map返回的內(nèi)容print出來,可以得到這樣一個結(jié)果:>>> print(map(dis, points))0x107aad1d0>這是一個類的標準輸出,其實它返回的不是最后的結(jié)果,而是一個迭代器。我們在之前的文章當(dāng)中已經(jīng)介紹過了迭代器和生成器的相關(guān)概念,這里不多做贅述了,遺忘的同學(xué)可以點擊下方鏈接回顧一下之前的內(nèi)容:
Python——五分鐘帶你弄懂迭代器與生成器,夯實代碼能力
我們想要獲得完整的內(nèi)容也很容易,我們只需要將它轉(zhuǎn)化成list類型即可:>>> print(list(map(dis, points)))[1.0, 4.47213595499958, 3.605551275463989]以上過程還可以進一步簡化,還記得我們之前介紹過的匿名函數(shù)嗎?由于dis函數(shù)在我們的程序當(dāng)中只會在map中用到,我們完全沒有必要單獨創(chuàng)建一個函數(shù),我們可以直接傳入一個匿名函數(shù)搞定運算:map(lambda x: math.sqrt(x[0]**2 + x[1] ** 2), points)簡單總結(jié)一下,map操作其實執(zhí)行的是一個映射。它可以自動地將一個序列當(dāng)中的內(nèi)容通過制定的函數(shù)映射成另一個序列,從而避免顯式地使用循環(huán)來調(diào)用,在很多場景下可以大大地簡化代碼的編寫,可以很方便地將一個序列整體轉(zhuǎn)變成另一個結(jié)果。
reduce
相比于map,reduce的操作稍稍難理解一點點。它也是規(guī)定一個映射,不過不是將一個元素映射成一個結(jié)果。而是將兩個元素歸并成一個結(jié)果。并且它并不是調(diào)用一次,而是依次調(diào)用,直到最后只剩下一個結(jié)果為止。比如說我們有一個數(shù)組[a, b, c, d]和一個函數(shù)f,我們計算reduce(f, [a, b, c, d])其實就等價于f(f(f(a, b), c), d)。和map不同的是,reduce最后得到一個結(jié)果,而不是一個迭代器或者是list。我們光說有些抽象,不妨來看一個例子,就看最簡單的一個例子:reduce函數(shù)接收兩個數(shù),返回兩個數(shù)的和。那么顯然,我們依次調(diào)用reduce,得到的就是原數(shù)組的和。from functools import reducedef f(a, b):return a + bprint(reduce(f, [1, 2, 3, 4]))最終得到的結(jié)果當(dāng)然是10,同樣,我們也可以將reduce中的方法定義成匿名函數(shù),一樣不影響最終的結(jié)果。print(reduce(lambda x, y: x + y, [1, 2, 3, 4]))
MapReduce
既然我們map和reduce都有了,顯然我們可以將它們串聯(lián)起來使用,也就是分布式系統(tǒng)當(dāng)中MapReduce的做法。雖然如果不手動使用線程池的話,Python并不會起多個線程來加速運算,但是至少可以簡化我們實現(xiàn)的代碼。我們還是舉經(jīng)典的wordCount的例子,也就是文本計算詞頻。套用map和reduce的功能,整個流程非常清晰,我們只需要在map階段對文本進行分詞,在reduce階段對分詞之后的結(jié)果進行匯總即可。聽著好像非常容易,但是你實際去上手是寫不出來的。原因也很簡單,因為hadoop當(dāng)中的Map和Reduce中間還有一層shuffle的操作,會自動地將key值相同的結(jié)果放到同一個reducer當(dāng)中。在這個問題當(dāng)中,key自然就是我們的word,由于相同的word被放到同一個reducer當(dāng)中,我們只需要累加就行了。但是如果我們自己編寫mapreduce的話,由于缺少了中間數(shù)據(jù)重排的步驟,所以導(dǎo)致不能實現(xiàn)。要解決也簡單,我們可以人為增加一個map階段代替hadoop當(dāng)中的重排。相當(dāng)于做了一個MapMapReduce,我們來看代碼:from collections import Counter, defaultdicttexts = ['apple bear peach grape', 'grape orange pear']# 第一次map,將字符串轉(zhuǎn)成數(shù)組,每個單詞對應(yīng)1def mp1(text):
ret = []
words = text.split(' ')for word in words:
ret.append((word, 1))return ret# 第二次map,將數(shù)組轉(zhuǎn)成dictdef mp2(arr):
d = defaultdict(int)for k, v in arr:
d[k] += vreturn d# reduce,合并dictdef rd(x, y):
x.update(y)return x
print(reduce(rd, map(mp2, map(mp1, texts))))那如果我們不用多次MapReduce呢?也不是沒有辦法,需要取點巧,方法也簡單只要使用之前我們講解過的Counter類,就可以完美解決這個問題。我們來看代碼:from collections import Counter
texts = ['apple bear peach grape', 'grape orange pear']def mp(text):
words = text.split(' ')return Counter(words)
print(reduce(lambda x, y: x + y, map(mp, texts)))由于我們使用了Counter,所以我們在map階段返回的結(jié)果就已經(jīng)是詞頻的dict了,而在reduce階段我們只需要將它們?nèi)坷奂悠饋砭蚈K了。最后,我們來看下filter。
filter
filter的英文是過濾,所以它的使用就很明顯了。它的用法和map有些類似,我們編寫一個函數(shù)來判斷元素是否合法。通過調(diào)用filter,會自動將這個函數(shù)應(yīng)用到容器當(dāng)中所有的元素上,最后只會保留運行結(jié)果是True的元素,而過濾掉那些是False的元素。舉個例子,假設(shè)我們想要保留list當(dāng)中的奇數(shù)而過濾掉偶數(shù),我們當(dāng)然可以直接操作,比如:arr = [1, 3, 2, 4, 5, 8][i for i in arr if i % 2 > 0 ]而使用filter會非常方便:list(filter(lambda x: x % 2 > 0, arr))從這個例子當(dāng)中可能看不出便捷,但是有的時候判斷的條件可能非常復(fù)雜,我們判斷的邏輯不能簡單地在list定義當(dāng)中表達出來,這個時候使用filter則會容易得多。最后, 我們再看一個類似的用法。在itertools當(dāng)中有一個方法叫做 compress,通過compress我們可以實現(xiàn)根據(jù)一個序列的條件過濾另一個序列。舉個簡單的例子,假設(shè),我們有兩個數(shù)組:student = ['xiaoming', 'xiaohong', 'xiaoli', 'emily']
scores = [60, 70, 80, 40]我們想要獲取所有考試及格的同學(xué)的list,如果用常規(guī)做法基本上免不了使用循環(huán),但是使用compress可以很方便地通過一行代碼實現(xiàn):from itemtools import compress>>> pass = [i > 60 for i in scores]>>> print(pass)
[False, True, True, False]>>> list(compress(student, pass))
['xiaohong', 'xiaoli']需要注意的是filter和compress返回的都是一個迭代器,我們要獲取它們的值,需要手動轉(zhuǎn)換成list。雖然在日常的開發(fā)當(dāng)中不使用這三樣神器同樣可以工作,但是用上它們之后,會提升很多代碼的可讀性,節(jié)省很多無用的代碼。尤其是在面試的時候,很有可能就會給面試官留下不一樣的印象,也許結(jié)果也會不同。今天的文章就是這些,如果覺得有所收獲,請順手點個在看或者轉(zhuǎn)發(fā)吧,你們的舉手之勞對我來說很重要。
總結(jié)
以上是生活随笔為你收集整理的c++ map用法_Python专题——五分钟带你了解map、reduce和filter的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker安装gitlab_Gitla
- 下一篇: c++ properties_Java怎