python自學日記7——字典

學會把複雜問題拆解成本身已經掌握的基礎問題纔是正確的學習之道python

1.編寫一個函數,讀入words.txt,並將它們做爲鍵保存到一個字典中

後面還有使用in檢查某單詞是否在字典中,按說這個並不難,先讀取單詞表,而後經過將單詞做爲鍵,值用空字符就能夠了,而後代碼以下:編程

def read_dict():
    fin=open('words.txt')
    words_dict={}
    for line in fin:
        word=line.split()
        words_dict[word]=''
    return words_dict
read_dict()
TypeError                                 Traceback (most recent call last)
<ipython-input-18-59d842fe37d6> in <module>
      7         words_dict[word]=''
      8     return words_dict
----> 9 read_dict()

<ipython-input-18-59d842fe37d6> in read_dict()
      5     for line in fin:
      6         word=line.split()
----> 7         words_dict[word]=''
      8     return words_dict
      9 read_dict()

TypeError: unhashable type: 'list'

可是報錯了,具體緣由也弄不清楚,只能先把循環單獨拿出來比對一下app

fin=open('words.txt')
for line in fin:
    word=line.split()
    print(word)
['aa']
['aah']
['aahed']
['aahing']
['aahs']
['aal']
['aalii']
['aaliis']
['aals']

顯示的是這樣的,我記得前面讀取的時候沒有中括號,仔細看發現錯在word=line.split(),split是作分割用的,原本這裏應該用strip去空格的,只憑記憶寫的記混了,而後改一下函數

def read_dict():
    fin=open('words.txt')
    words_dict={}
    for line in fin:
        word=line.split()
        words_dict[word]=''
    return words_dict
read_dict()

此次顯示就正常了,若是隻到這沒下面的檢查單詞是否在字典中這段代碼是沒有問題的,可是要檢查一個單詞是否在字典的鍵中就須要用到字典,而在函數中字典是局部引用,無法在別處使用的,因此當檢查單詞是否在字典中時會報錯:words_dict沒有被定義,因此須要把它放到函數外面,最終改爲以下:學習

fin=open('words.txt')
words_dict={}
def read_dict():
    
    for line in fin:
        word=line.strip()
        words_dict[word]=''
    return words_dict
read_dict()
'hello' in words_dict

代碼是輸出正常了,可是總以爲這個方法有點怪,也許會有更好的方法,後面找到再說。測試

2.使用字典做爲計數器集合

def histogram(s):
    d=dict()
    for c in s:
        if c not in d:
            d[c]=1
        else:
            d[c]+=1
    return d
h=histogram('faljgaldkjalgkjeweraldfjsl')
print(h)
{'f': 2, 'a': 4, 'l': 5, 'j': 4, 'g': 2, 'd': 2, 'k': 2, 'e': 2, 'w': 1, 'r': 1, 's': 1}

這是比較常規的作法,字典有一個方法get,接收一個鍵和一個默認值,若是鍵出如今字典中,get返回對應的值,不然返回默認值,接下來用get來替代上面的代碼code

def histogram(s):
    d=dict()
    for c in s:
        d[c]=int(d.get(c,'0'))+1 
    return d
h=histogram('faljgaldkjalgkjeweraldfjsl')
print(h)

get默認值設爲0,若是c不在d,返回0,經過加1,d[c]=1,下次再檢查這個值時,由於在d中會返回1,再經過加一變成2,這樣就經過循環得出結果,省去了判斷條件對象

3.反轉字典

將原字典的值變爲新字典的鍵,原字典的鍵變爲新字典的值。ip

原來的方法仍是經過鍵來作遍歷,而後每次將對應的值去和新的字典中去比對,若是沒有新增一個鍵值對,若是有了只在原來的值上增長一個新值字符串

def invert_dict(d):
    invert=dict()
    for key in d:
        val=d[key]
        if val not in invert:
            invert[val]=[key]
        else:
            invert[val].append(key)
    return invert
d=histogram('parrot')
print(d)
invert_dict(d)
{'p': 1, 'a': 1, 'r': 2, 'o': 1, 't': 1}
{1: ['p', 'a', 'o', 't'], 2: ['r']}

字典有個方法setdefault,經過這個方法將上面的函數寫得更簡潔些:

setdefault(key['default']):若是字典存在鍵 key ,返回它的值。若是不存在,插入值爲 default 的鍵 key ,並返回 default 。 default 默認爲 None。

按照上面的描述須要先作幾個實驗,由於咱們須要在空字典裏新增鍵值對,須要用空字典測試一下setdefault方法

a=dict()
a.setdefault('b',1)

返回值是1,print(a)返回是{'b': 1},這樣說若是字典裏沒有就會按照括號裏的內容變成鍵值對放到字典裏,再測試下

a.setdefault('b',2)
print(a)

返回值仍是{'b': 1},這樣基本上就懂了,若是已經存在返回仍是1,咱們須要在循環時若是鍵已經存在字典中須要增長鍵的值,那麼剛開始設置爲空字符,不過須要測試下類型:

type(a.setdefault('a',''))

返回值是str,那麼就再測試下用list能不能將空字符串轉換爲列表

list(a.setdefault('a',''))

返回值是[],那麼就能夠寫代碼了

def invert_dict(d):
    invert=dict()
    for key in d:
        val=d[key]
        invert[val]=list(invert.setdefault(val,'')).append(key)
    return invert
d=histogram('parrot')
invert_dict(d)
TypeError                                 Traceback (most recent call last)
<ipython-input-116-5d92649dd8a4> in <module>
      7     return invert
      8 d=histogram('parrot')
----> 9 invert_dict(d)

<ipython-input-116-5d92649dd8a4> in invert_dict(d)
      4     for key in d:
      5         val=d[key]
----> 6         invert[val]=list(invert.setdefault(val,'')).append(key)
      7     return invert
      8 d=histogram('parrot')

TypeError: 'NoneType' object is not iterable

上網查了下報錯緣由說通常發生在將None賦給多個值時,仍是須要先拆解成小代碼塊檢查

b=dict()
b['a']=list(b.setdefault('a','')).append('hello')
print(b)

返回值是{'a': None},原本預期是後面變成hello結果用append沒有效果,換「+」試試

b=dict()
b['a']=list(b.setdefault('a',''))+['hello']
print(b)
{'a': ['hello']}

此次返回值卻是正常了,上面報錯看出是用append鍵的值都是None才報錯的,下面將append改爲「+」

def invert_dict(d):
    invert=dict()
    for key in d:
        val=d[key]
        invert[val]=list(invert.setdefault(val,''))+[key]
    return invert
d=histogram('parrot')
invert_dict(d)

此次返回結果是正常的了。

看了答案代碼以下

def invert_dict(d):
    """Inverts a dictionary, returning a map from val to a list of keys.

    If the mapping key->val appears in d, then in the new dictionary
    val maps to a list that includes key.

    d: dict

    Returns: dict
    """
    inverse = {}
    for key, val in d.items():
        inverse.setdefault(val, []).append(key)
    return inverse


if __name__ == '__main__':
    d = dict(a=1, b=2, c=3, z=1)
    inverse = invert_dict(d)
#     for val, keys in inverse.items():
#         print( val, keys)
    print(inverse)

發現了幾個問題,首先我不知道字典能夠用for key, val in d.items(),這樣能夠節省一些代碼,dict.items(返回的對象是一個動態試圖,當字典變是,視圖也會變。

另外答案用的是inverse.setdefault(val, []).append(key),而不是用將值賦給value,就說明我對這個setdefault並無徹底理解,另外我也發現了一個問題,我用的是' ',答案用的是[],卻是省了再轉化成list了。還一個讓我更清楚的是有返回值和沒有返回值的狀況,例如

[1,2]+[3]

返回值是[1,2,3]

可是用[1,2].append('3'),返回值是None,這也就說明了爲何會在前面報上面的錯誤。

4.編寫一個程序,讀入單詞表,並找到全部輪轉對。

輪轉對:兩個單詞,若是可使用輪轉操做將一個轉換爲另外一個,則成爲輪轉對。例如ad輪轉一步變爲be。

遇到一個大的問題沒頭緒首先要想一下能將這個問題分解成哪些已經作過的,讀入單詞表這個之前作過了,輪轉操做在ROT13那個練習中也作過了。那麼大致思路就是讀入單詞表,用遍歷方式將每一個單詞輪轉1到25步,由於26步是自己,而後將輪轉後的單詞查看是否在單詞表中,若是在就打印出來這兩個詞就能夠了。

import bisect
def rotate_word(word,num): #輪轉單詞
    new_word=''
    for letter in word:
        if letter.isupper():
            start=ord('A')
        elif letter.islower():
            start=ord('a')
        
        new_word=new_word+(chr((ord(letter)-start+num+26)%26+start))
    return new_word
# rotate_word('melon',-10)
def find_lt(a,x): #查找單詞是否在單詞表中
    i=bisect.bisect_left(a,x)
    if i != len(a) and a[i]==x:
        return True
    return None
def read_words(): #讀取單詞表
    fin=open('words.txt')
    t=[]
    for line in fin:
        word=line.strip()
        t.append(word)
    return t
def sdf():
    t=read_words()
    for s in t:
        for i in range(1,26):
            new_words=rotate_word(s,i)
            if find_lt(t,new_words):
                print(s,i,new_words)
sdf()

總結:注意一個方法或函數最後是有返回值仍是沒返回值的狀況。

從今天看出有些時候會發現答案給的代碼中會有一些內置函數或方法使得編程變得很簡單,這固然很好,因此應該多多閱讀標準庫。可是在不知道這個的狀況下也能作出來也很是好。就像剛開始學英語時,比較好的練習方式是用已掌握的一些簡單詞彙能把一些你沒遇到的復瑣事物或狀況描述出來。因此一是要多多掌握簡便的方法,也要學着把複雜問題轉換成本身已經掌握的方法來解決。

相關文章
相關標籤/搜索