《Python CookBook》讀書(shū)筆記-數(shù)據(jù)結(jié)構(gòu)和算法(二)

從序列中移除重復(fù)項(xiàng)且保持元素間順序不變

方法

可以用集合和生成器來(lái)解決

先來(lái)了解下什么是可哈希(hashable):
如果一個(gè)對(duì)象在自己的生命周期中有一哈希值(hash value)是不可改變的法绵,那么它就是可哈希的(hashable)的。可哈希對(duì)象是對(duì)象有hash(self)內(nèi)置函數(shù)的對(duì)象飞盆。對(duì)于可哈希的對(duì)象執(zhí)行這個(gè)函數(shù)將會(huì)返回一個(gè)整數(shù)沦零∑瓴剩可哈希對(duì)象判斷相等的唯一條件就是兩者的哈希值相等舰褪。Python中所有不可改變的的對(duì)象(imutable objects)都是可哈希的急黎,比如字符串健提,元組琳猫,也就是說(shuō)可改變的容器如字典,列表不可哈希(unhashable)私痹。我們用戶(hù)所定義的類(lèi)的實(shí)例對(duì)象默認(rèn)是可哈希的(hashable)脐嫂,它們都是唯一的统刮,而hash值也就是它們的id()。

t = (1, 2, 3)
s = '123'
l = [1,2,3]
d = [{'a': 1},{'b':2}]
print(t.__hash__())
print(s.__hash__())
print(l.__hash__) # list不是可哈希的
print(l[1].__hash__()) # list的對(duì)象可哈希
print(d.__hash__) # dict不是可哈希的
# set(d)            # 列表的元素是字典账千,字典是不可哈希的侥蒙,所以返回TypeError: unhashable type: 'dict'
print(set([(1,2), (1,2), (2,)])) # 列表的元素是元組,元組是可哈希的
2528502973977326415
-8527273320470595707
None
2
None
{(1, 2), (2,)}
# 當(dāng)序列中的元素是可哈希時(shí)
def dedupe(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)
            
a= [1, 5, 2, 1, 7, 5, 9 ,0]
b = set(a)
c = dedupe(a)
print(b)
print(list(c))
{0, 1, 2, 5, 7, 9}
[1, 5, 2, 7, 9, 0]
# 當(dāng)不確定序列中的元素是否可哈希時(shí)匀奏,需要對(duì)程序改造如下
def dedupe(items, key=None):
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(val)
            
a= [{'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
# b = set(a) # a的元素是字典鞭衩,字典不是可哈希的,所以返回TypeError: unhashable type: 'dict'
c = dedupe(a, key=lambda d: (d['x'], d['y']))
d = dedupe(a, key=lambda d: (d['x']))
print(list(c))
print(list(d))
[{'y': 2, 'x': 1}, {'y': 3, 'x': 1}, {'y': 4, 'x': 2}]
[{'y': 2, 'x': 1}, {'y': 4, 'x': 2}]
# 讀取一個(gè)文件娃善,去除其中的重復(fù)行
with open('a.txt', 'r') as f:
#     print(list(f)) # ['abc\n', 'a\n', 'df\n', 'abc\n', 'df\n', '123\n']
    print(list(dedupe(f))) # ['abc\n', 'a\n', 'df\n', '123\n']
['abc\n', 'a\n', 'df\n', '123\n']

找出序列中出現(xiàn)次數(shù)最多的元素

方法

可以用collections模塊中的Counter類(lèi)來(lái)實(shí)現(xiàn)
Counter的底層是一個(gè)字典论衍,在元素和它們出現(xiàn)的次數(shù)間做了一個(gè)映射。Counter對(duì)象提供任何可哈希的對(duì)象序列作為輸入聚磺。

from collections import Counter

words = ['a', 'a', 'b', 'a', 'e', 'f', 'a', 'e', 'e', 'd', 'd']
count = Counter(words)
print(count) 
print(count.most_common(3)) # 出現(xiàn)次數(shù)最多的前三個(gè)元素
Counter({'a': 4, 'e': 3, 'd': 2, 'f': 1, 'b': 1})
[('a', 4), ('e', 3), ('d', 2)]
print(count['f'])
count['f'] += 1 # 還可以手動(dòng)增加某個(gè)元素的出現(xiàn)次數(shù)
print(count['f'])
1
2
print(count)
words_2 = ['b', 'a', 'c']
count.update(words_2) # update方法可以更新count的數(shù)據(jù)
print(count)
Counter({'a': 8, 'e': 6, 'd': 4, 'f': 3, 'b': 2})
Counter({'a': 9, 'e': 6, 'd': 4, 'f': 3, 'b': 3, 'c': 1})
# Counter對(duì)象的各種運(yùn)算
a = Counter(words)
b = Counter(words_2)
print(a)
print(b)
print(a + b)
print(a- b)
Counter({'a': 4, 'e': 3, 'd': 2, 'f': 1, 'b': 1})
Counter({'c': 1, 'b': 1, 'a': 1})
Counter({'a': 5, 'e': 3, 'b': 2, 'd': 2, 'f': 1, 'c': 1})
Counter({'a': 3, 'e': 3, 'd': 2, 'f': 1})

對(duì)字典列表的排序

friends = [
    {'name': 'jlan', 'age': 27, 'gender': 'm'},
    {'name': 'lann', 'age': 25, 'gender': 'f'},
    {'name': 'bob', 'age': 23, 'gender': 'm'},
    {'name': 'herry', 'age': 28, 'gender': 'f'},
    {'name': 'dairy', 'age': 26, 'gender': 'm'}
]

print(friends)
from operator import itemgetter
print(sorted(friends, key=itemgetter('age')))
print(sorted(friends, key=itemgetter('age', 'name')))

# itemgetter()的參數(shù)可以是字典的鍵坯台、用數(shù)字表示的列表元素等任何可以穿給對(duì)象的__getitem__()方法的值。
# 用lambda也可以實(shí)現(xiàn)這樣的功能瘫寝,但是用itemgetter通常效率更高
print(sorted(friends, key=lambda f: f['age']))
print(sorted(friends, key=lambda f: (f['age'], f['name'])))
[{'gender': 'm', 'age': 27, 'name': 'jlan'}, {'gender': 'f', 'age': 25, 'name': 'lann'}, {'gender': 'm', 'age': 23, 'name': 'bob'}, {'gender': 'f', 'age': 28, 'name': 'herry'}, {'gender': 'm', 'age': 26, 'name': 'dairy'}]
[{'gender': 'm', 'age': 23, 'name': 'bob'}, {'gender': 'f', 'age': 25, 'name': 'lann'}, {'gender': 'm', 'age': 26, 'name': 'dairy'}, {'gender': 'm', 'age': 27, 'name': 'jlan'}, {'gender': 'f', 'age': 28, 'name': 'herry'}]
[{'gender': 'm', 'age': 23, 'name': 'bob'}, {'gender': 'f', 'age': 25, 'name': 'lann'}, {'gender': 'm', 'age': 26, 'name': 'dairy'}, {'gender': 'm', 'age': 27, 'name': 'jlan'}, {'gender': 'f', 'age': 28, 'name': 'herry'}]
[{'gender': 'm', 'age': 23, 'name': 'bob'}, {'gender': 'f', 'age': 25, 'name': 'lann'}, {'gender': 'm', 'age': 26, 'name': 'dairy'}, {'gender': 'm', 'age': 27, 'name': 'jlan'}, {'gender': 'f', 'age': 28, 'name': 'herry'}]
[{'gender': 'm', 'age': 23, 'name': 'bob'}, {'gender': 'f', 'age': 25, 'name': 'lann'}, {'gender': 'm', 'age': 26, 'name': 'dairy'}, {'gender': 'm', 'age': 27, 'name': 'jlan'}, {'gender': 'f', 'age': 28, 'name': 'herry'}]
# key=itemgetter()或lambda方法同樣也可以用于min蜒蕾,max之類(lèi)的函數(shù)

根據(jù)字段將記錄分組

用itertools.groupby()方法

from operator import itemgetter
from itertools import groupby

# 字符串壓縮,面試經(jīng)常會(huì)出現(xiàn)這樣的問(wèn)題
l = 'aabbbbcccddeddff'
for key, group in groupby(l):
    print(key)
    print(list(group))
a
['a', 'a']
b
['b', 'b', 'b', 'b']
c
['c', 'c', 'c']
d
['d', 'd']
e
['e']
d
['d', 'd']
f
['f', 'f']
friends = [
    {'name': 'jlan', 'age': 27, 'gender': 'm'},
    {'name': 'lann', 'age': 25, 'gender': 'f'},
    {'name': 'bob', 'age': 23, 'gender': 'm'},
    {'name': 'herry', 'age': 28, 'gender': 'f'},
    {'name': 'dairy', 'age': 26, 'gender': 'm'}
]
# 對(duì)friends按性別分組
friends.sort(key=itemgetter('gender'))
for key, group in groupby(friends, key=itemgetter('gender')):
    print(key)
    print(list(group))
f
[{'gender': 'f', 'age': 25, 'name': 'lann'}, {'gender': 'f', 'age': 28, 'name': 'herry'}]
m
[{'gender': 'm', 'age': 27, 'name': 'jlan'}, {'gender': 'm', 'age': 23, 'name': 'bob'}, {'gender': 'm', 'age': 26, 'name': 'dairy'}]

說(shuō)明

groupby()方法通過(guò)掃描序列找出擁有相同值(或是由參數(shù)key指定的函數(shù)返回的值)的序列項(xiàng)焕阿,并將它們分組咪啡。groupby()創(chuàng)建了一個(gè)迭代器,每次迭代都返回一個(gè)值(分組的key)和一個(gè)子迭代器(屬于該分組的group)捣鲸。對(duì)與friends這樣序列如果要按照性別分組瑟匆,需要先對(duì)friends按性別進(jìn)行排序,把相同性別的項(xiàng)放在一塊栽惶,然后才能按groupby()進(jìn)行分組愁溜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市外厂,隨后出現(xiàn)的幾起案子冕象,更是在濱河造成了極大的恐慌,老刑警劉巖汁蝶,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渐扮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡掖棉,警方通過(guò)查閱死者的電腦和手機(jī)墓律,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)幔亥,“玉大人耻讽,你說(shuō)我怎么就攤上這事∨撩蓿” “怎么了针肥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵饼记,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我慰枕,道長(zhǎng)具则,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任具帮,我火速辦了婚禮博肋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匕坯。我一直安慰自己束昵,他們只是感情好拔稳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布葛峻。 她就那樣靜靜地躺著,像睡著了一般巴比。 火紅的嫁衣襯著肌膚如雪术奖。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天轻绞,我揣著相機(jī)與錄音采记,去河邊找鬼。 笑死政勃,一個(gè)胖子當(dāng)著我的面吹牛唧龄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奸远,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼既棺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了懒叛?” 一聲冷哼從身側(cè)響起丸冕,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薛窥,沒(méi)想到半個(gè)月后胖烛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诅迷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年佩番,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罢杉。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡趟畏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屑那,到底是詐尸還是另有隱情拱镐,我是刑警寧澤艘款,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沃琅,受9級(jí)特大地震影響哗咆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜益眉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一晌柬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧郭脂,春花似錦驰唬、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至莹弊,卻和暖如春涤久,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忍弛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工响迂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人细疚。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓蔗彤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親疯兼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子然遏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容