2013-10-05 46 views
1

閱讀我去嵌套字典的方法是這樣的:大廈嵌套的字典中一行行從文件

dicty = dict() 
tmp = dict() 
tmp["a"] = 1 
tmp["b"] = 2 
dicty["A"] = tmp 

dicty == {"A" : {"a" : 1, "b" : 1}} 

當我嘗試實現這個一個大文件的問題開始,讀取一行線。 這是打印每行的內容在列表中:

['proA', 'macbook', '0.666667'] 
['proA', 'smart', '0.666667'] 
['proA', 'ssd', '0.666667'] 
['FrontPage', 'frontpage', '0.710145'] 
['FrontPage', 'troubleshooting', '0.971014'] 

我想與嵌套的字典落得(忽略小數):

{'FrontPage': {'frontpage': '0.710145', 'troubleshooting': '0.971014'}, 
'proA': {'macbook': '0.666667', 'smart': '0.666667', 'ssd': '0.666667'}} 

由於我在一行行讀,我必須檢查文件中是否還有第一個單詞(它們都是分組的),然後再將它作爲完整的詞典添加到較高的字典中。

這是我實現:

def doubleDict(filename): 
    dicty = dict() 
    with open(filename, "r") as f: 
     row = 0 
     tmp = dict() 
     oldword = "" 
     for line in f: 
      values = line.rstrip().split(" ") 
      print(values) 
      if oldword == values[0]: 
       tmp[values[1]] = values[2] 
      else: 
       if oldword is not "": 
        dicty[oldword] = tmp 
       tmp.clear() 
       oldword = values[0] 
       tmp[values[1]] = values[2] 
      row += 1 
      if row % 25 == 0: 
       print(dicty) 
       break #print(row) 
    return(dicty) 

我真的喜歡這個在熊貓,但現在我會很高興,如果這將是一個字典工作。出於某種原因,在剛讀完前5行後,我最終得到:

{'proA': {'frontpage': '0.710145', 'troubleshooting': '0.971014'}}, 

這顯然是不正確的。哪裏不對?

+0

'{frontpage:0.7,{troubleshooting:0.97}}'不是有效的字典。字典只能有鍵值對;你有一個鍵值對加上一個無鍵值。 (如果你想'{'frontpage':(0.7,{'troubleshooting':0.97})}',你需要圍繞該元組的parens。) – abarnert

+0

我想我解決了它,一個捲曲丟失了。而且,它們當然是字符串。 – PascalVKooten

+0

另外,用'is'比較字符串是一件冒險的事情。你一定會放棄它,特別是因爲沒有實習的機會非常渺茫,但你不應該指望這一點。 – abarnert

回答

2

使用collections.defaultdict() object爲自動實例化的嵌套字典:

from collections import defaultdict 

def doubleDict(filename): 
    dicty = defaultdict(dict) 
    with open(filename, "r") as f: 
     for i, line in enumerate(f): 
      outer, inner, value = line.split() 
      dicty[outer][inner] = value 
      if i % 25 == 0: 
       print(dicty) 
       break #print(row) 
    return(dicty) 

我以前enumerate()並生成線條這裏算;比保持一個單獨的櫃檯簡單得多。

即使沒有defaultdict,也可以讓外部字典保留對嵌套字典的引用,並使用values[0]再次檢索它;沒有必要保持temp參考周圍:

>>> dicty = {} 
>>> dicty['A'] = {} 
>>> dicty['A']['a'] = 1 
>>> dicty['A']['b'] = 2 
>>> dicty 
{'A': {'a': 1, 'b': 1}} 

所有defaultdict那麼確實是讓我們不必測試,如果我們已經創建了一個嵌套的字典。相反的:

if outer not in dicty: 
    dicty[outer] = {} 
dicty[outer][inner] = value 

我們簡單地忽略if試驗,defaultdict將創建一個新的字典對我們來說,如果關鍵是尚未出現。

+0

謝謝,這個解決方案非常好/整潔/快速。 – PascalVKooten

+0

是的,我過去曾嘗試過很多事情,我記得沒有的關鍵是一個問題。 – PascalVKooten

1

儘管這不是完成任務的理想方式,但您已經非常接近使其工作。

您的主要問題是您正在重複使用相同的tmp字典。在第一個鍵下插入dicty之後,然後您將它填入clear並開始填充新值。替換tmp.clear()tmp = {}來解決這個問題,所以你有一個不同的字典爲每個鍵,而不是所有鍵相同的一個。

你的第二個問題是,當你到達結尾時,你永遠不會在字典中存儲最後的tmp值,所以在for循環後面添加另一個dicty[oldword] = tmp

您的第三個問題是您正在檢查if oldword is not "":。這可能是真的,即使它是一個空字符串,因爲你比較的是身份而不是平等。只需將其更改爲if oldword:即可。 (這一個,你通常會逃脫,因爲小字符串通常是被禁止的,通常會共享身份...但是你不應該指望它。)

如果你解決了這兩個問題,你會得到:

{'FrontPage': {'frontpage': '0.710145', 'troubleshooting': '0.971014'}, 
'proA': {'macbook': '0.666667', 'smart': '0.666667', 'ssd': '0.666667'}} 

我不知道如何將其轉換爲您聲稱想要的格式,因爲該格式甚至不是有效的字典。但希望這會讓你接近。


有兩種簡單的方法來做到這一點:

  • 組與值,例如,itertools.groupby,接着變換每一組成一個字典,並插入它都在同一個步驟。這與您現有的代碼一樣,要求輸入已經被values[0]分批處理。
  • 將字典用作字典。你可以查找每個鍵進來並添加到值,如果找到了,創建一個新的,如果沒有。一個defaultdictsetdefault方法將使這個簡潔,但即使你不知道這些,它很容易明確寫出來,它仍然不會比你現在擁有的冗長。

第二個版本已經在Martijn Pieters的回答中很好地解釋了。

首先可以這樣寫:

def doubleDict(s): 
    with open(filename, "r") as f: 
     rows = (line.rstrip().split(" ") for line in f) 
     return {k: {values[1]: values[2] for values in g} 
       for k, g in itertools.groupby(rows, key=operator.itemgetter(0))} 

當然,每25行後不打印出來的字典到目前爲止,但是這很容易通過轉動理解成一個顯式循環添加(並理想地使用enumerate而不是保留明確的row計數器)。

+0

是的,我認爲這只是我的一個格式化失敗。我會複製你的輸出,因爲這是我尋求的格式。感謝您展示我的代碼出了什麼問題,而不是提出現有的問題。 – PascalVKooten