2014-07-24 86 views
0

我從介紹性的Python教科書中學習python,但遇到以下問題:爲什麼我會收到空​​字典?

您將實現函數index(),其中輸入文本文件的名稱和單詞列表。對於列表中的每一個單詞,您的功能都將找到出現單詞的文本文件中的行並打印相應的行號。

例:

>>>> index('raven.txt', ['raven', 'mortal', 'dying', 'ghost', 'ghastly', 'evil', 'demon']) 

ghost  9 
dying  9 
demon  122 
evil  99, 106 
ghastly 82 
mortal 30 
raven  44, 53, 55, 64, 78, 97, 104, 111, 118, 120 

這是我試圖在這個問題:

def index(filename, lst): 
    infile = open(filename, 'r') 
    lines = infile.readlines() 
    lst = [] 
    dic = {} 
    for line in lines: 
     words = line.split() 
     lst. append(words) 
    for i in range(len(lst)): 
     for j in range(len(lst[i])): 
      if lst[i][j] in lst: 
       dic[lst[i][j]] = i 
    return dic 

當我運行的功能,我回來一個空的字典。我不明白我爲什麼得到一本空字典。那麼我的功能有什麼問題?謝謝。

+2

您將在'lst = []'行中將'[]'重新賦值給給定的參數'lst'。這只是一個錯字。 – soon

+2

說實話,這個邏輯在很多方面都是錯誤的。我建議你首先重新審視你試圖實現的算法。 – NPE

回答

1

您將覆蓋lst的值。您將它作爲函數的參數(在這種情況下,它是一個字符串列表)和文件中的單詞列表(在這種情況下,它是一個字符串列表的列表)。當你這樣做:

if lst[i][j] in lst 

比較總是返回False因爲lst[i][j]str,但lst包含字符串只列出,而不是字符串本身。這意味着dic的分配不會執行,因此會得到一個空的dict

爲了避免這種情況,你應該爲你存儲詞列表使用不同的名稱,例如:

In [4]: !echo 'a b c\nd e f' > test.txt 

In [5]: def index(filename, lst): 
    ...:  infile = open(filename, 'r') 
    ...:  lines = infile.readlines() 
    ...:  words = [] 
    ...:  dic = {} 
    ...:  for line in lines: 
    ...:   line_words = line.split() 
    ...:   words.append(line_words) 
    ...:  for i in range(len(words)): 
    ...:   for j in range(len(words[i])): 
    ...:    if words[i][j] in lst: 
    ...:     dic[words[i][j]] = i 
    ...:  return dic 
    ...: 

In [6]: index('test.txt', ['a', 'b', 'c']) 
Out[6]: {'a': 0, 'c': 0, 'b': 0} 

也有很多的事情可以發生改變。

當你想迭代一個列表時,你不必顯式地使用索引。如果你需要的指數,你可以使用enumerate

for i, line_words in enumerate(words): 
     for word in line_words: 
      if word in lst: dict[word] = i 

您也可以直接迭代上的一個文件(參閱更多的信息蟒蛇教程Reading and Writing Files部分):

# use the with statement to make sure that the file gets closed 
with open('test.txt') as infile: 
    for i, line in enumerate(infile): 
     print('Line {}: {}'.format(i, line)) 

事實上我不明白你爲什麼會先建立那個words列表。只是itertate直接在構建字典文件:

def index(filename, lst): 
    with open(filename, 'r') as infile: 
     dic = {} 
     for i, line in enumerate(infile): 
      for word in line.split(): 
       if word in lst: 
        dic[word] = i 
    return dic 

dic值應該名單,因爲多行包含相同的字。因爲它代表你dic只會保存最後一行,其中一個字發現:

from collections import defaultdict 

def index(filename, words): 
    # make faster the in check afterwards 
    words = frozenset(words) 
    with open(filename) as infile: 
     dic = defaultdict(list) 
     for i, line in enumerate(infile): 
      for word in line.split(): 
       if word in words: 
        dic[word].append(i) 
    return dic 

如果你不想使用collections.defaultdict可以用dic = {}替代dic = defaultdict(list),然後改變:

dic[word].append(i) 

有了:

if word in dic: 
    dic[word] = [i] 
else: 
    dic[word].append(i) 

,或者,你可以使用dict.setdefault

dic.setdefault(word, []).append(i) 

雖然這最後一種方式比原始代碼慢一點。

請注意,所有這些解決方案的屬性,如果在文件中找不到一個單詞它根本不會出現在結果中。但是,您可能希望在結果中使用emty列表作爲值。在這種情況下,它更簡單的dict以空列表開始循環,如以前:

dic = {word : [] for word in words} 
for i, line in enumerate(infile): 
    for word in line.split(): 
     if word in words: 
      dic[word].append(i) 

參考文檔中關於List ComprehensionsDictionaries,瞭解第一線。然而

dic = {word : [] for word in words} 
for i, line in enumerate(infile): 
    for word in words: 
     if word in line.split(): 
      dic[word].append(i) 

注意,這將是慢,因爲:

您還可以重複words的替代線路,這樣

  • line.split()返回一個列表,所以word in line.split()會必須掃描所有列表。
  • 您正在重複計算line.split()

您可以嘗試解決這兩個問題做:

dic = {word : [] for word in words} 
for i, line in enumerate(infile): 
    line_words = frozenset(line.split()) 
    for word in words: 
     if word in line_words: 
      dic[word].append(i) 

請注意,在這裏我們在line.split()一次迭代打造集也超過words。根據兩組的大小,這可能比原始版本更慢或更快(迭代超過line.split())。

但是在這一點上,它可能更快地相交集:

dic = {word : [] for word in words} 
for i, line in enumerate(infile): 
    line_words = frozenset(line.split()) 
    for word in words & line_words: # & stands for set intersection 
     dic[word].append(i) 
+0

非常感謝您的詳細回覆。回顧一下這個問題,我忘記了我已經把這個函數作爲輸入。所以,我有點不好意思問這樣一個簡單的問題。儘管如此,感謝您的回覆。我從中學到了很多東西。 – Quino

1

試試這個,

def index(filename, lst): 
    dic = {w:[] for w in lst} 
    for n,line in enumerate(open(filename,'r')): 
     for word in lst: 
      if word in line.split(' '): 
       dic[word].append(n+1) 
    return dic 

這裏有介紹的語言,你應該知道的,因爲他們將在長期內的生活帶來便利的某些功能。

第一個是字典理解。它基本上使用lst中的詞作爲鍵和空列表[]作爲每個鍵的值來初始化字典。

接下來的enumerate命令。這允許我們迭代序列中的項目,但也給了我們這些項目的索引。在這種情況下,因爲我們傳遞了一個文件對象到enumerate它將循環播放。對於每次迭代,n將是該行的基於0的索引,並且line將是該行本身。接下來我們遍歷lst中的單詞。

請注意,我們在這裏不需要任何索引。 Python鼓勵循環遍歷序列中的對象,而不是遍歷索引,然後基於索引訪問序列中的對象(例如,不鼓勵做for i in range(len(lst)): do something with lst[i])

最後,in運算符是測試多種類型的成員資格的非常直接的方法對象和語法是非常直觀的。在這種情況下,我們要求的是從lst當前line當前的單詞。我們使用line.split(' ')

注獲得的該行中的單詞的列表。如果我們不't do this,'the' in 'there was a ghost' will return True as the是其中一個單詞的子串。另一方面'the' in ['there', 'was', 'a', 'ghost']將返回False。如果條件返回True,我們將它附加到與我們的字典中的鍵相關聯的列表中。

這可能是很多咀嚼,但這些概念使這樣的問題更直接。

0

首先,用的話你的函數參數是名爲lst也是,你把所有的單詞的列表中的文件也被命名lst,所以你沒有保存傳遞給你的函數的單詞,因爲在第4行中,你正在重新聲明列表。

其次,您正在遍歷文件中的每一行(第一個for),並獲取該行中的單詞。之後,lst包含整個文件中的所有單詞。因此,在for i ...中,您正在遍歷文件中的所有單詞,因此無需使用第三個for j,您可以在每個單詞中遍歷每個字符。

在簡歷中,那if你說的是「如果這個單個字符在單詞列表中......」這個不是,所以字典永遠不會填滿。

for i in range(len(lst)): 
    if words[i] in lst: 
    dic[words[i]] = dic[words[i]] + i # To count repetitions 

你需要重新思考的問題,甚至因爲在字典中的字將不存在給了一個錯誤我的答案會失敗,但你明白了吧。祝你好運!

相關問題