2015-11-07 45 views
0

我解析多個網站,並試圖建立一個哈希看起來像:追加到一個數組值在哈希

"word" => [[01.html, 2], [02.html, 7], [03.html, 4]] 

其中單詞是在索引中給定的字,在每個第一值子列表是找到它的文件,第二個值是該給定文件中出現的次數。

我遇到了一個問題,它不是在值列表中添加["02.html", 7],而是爲「單詞」創建一個全新條目,並將["02.html", 7]放在哈希末尾。這導致基本上給我所有我的網站相互追加的單個索引,而不是給我一個主索引。

這裏是我的代碼:

for token in tokens 
    if !invindex.include?(token) 
    invindex[token] = [[doc_name, 1]] #adds the word to the hash with the doc name and occurrence of 1 
    else 
    for list in invindex[token] 
     if list[0] == doc_name 
     list[1] += 1 #adds one to the occurrence with the same doc_name 
     else 
     invindex[token].insert([doc_name, 1]) #this SHOULD append the doc name and initial occurrence inside the word's value list since the word is already in the hash 
     end 
    end 
    end 
end 
end 

希望這件事情簡單,我只是錯過了一些東西,當我跟蹤它在紙面上。

回答

1

我遇到了一個問題,而不是追加[「02.html」,7]的數值列表裏面 ,它創造了「字」, 放[「02一個全新的項目。 html「,7]在散列末尾。

我沒有看到的是:

invindex = { 
    word1: [ 
    ['01.html', 2], 
    ] 
} 

tokens = %i[ 
    word1 
    word2 
    word3 
] 

doc_name = '02.html' 

tokens.each do |token| 
    if !invindex.include?(token) 
    invindex[token] = [[doc_name, 1]] #adds the word to the hash with the doc name and occurrence of 1 
    else 
    invindex[token].each do |list| 
     if list[0] == doc_name 
     list[1] += 1 #adds one to the occurrence with the same doc_name 
     else 
     invindex[token].insert([doc_name, 1]) #this SHOULD append the doc name and initial occurrence inside the word's value list since the word is already in the hash 
     end 
    end 
    end 

end 

p invindex 

--output:-- 
{:word1=>[["01.html", 2]], :word2=>[["02.html", 1]], :word3=>[["02.html", 1]]} 

invindex[token].insert([doc_name, 1]) #this SHOULD append the doc name

都能跟得上:

invindex = { 
    word: [ 
    ['01.html', 2], 
    ] 
} 

token = :word 
doc_name = '02.html' 

invindex[token].insert([doc_name, 7]) 
p invindex 
invindex[token].insert(-1, ["02.html", 7]) 
p invindex 

--output:-- 
{:word=>[["01.html", 2]]} 
{:word=>[["01.html", 2], ["02.html", 7]]} 

Array#insert()需要指定一個索引作爲第一個參數。一般來說,當你想添加一些東西到最後,你用<<

invindex = { 
    word: [ 
    ['01.html', 2], 
    ] 
} 

token = :word 
doc_name = '02.html' 

invindex[token] << [doc_name, 7] 
p invindex 

--output:-- 
{:word=>[["01.html", 2], ["02.html", 7]]} 

for token in tokens

Ruby開發者不使用for-in循環,因爲,在循環中調用each(),所以Ruby開發者調用each()直接:

tokens.each do |token| 
    ... 
end 

最後,indenting in ruby是2個空格 - 不是3個空格,而不是1個空格,而不是4個空格。它是2個空格。

運用一切都交給你的代碼:

invindex = { 
    word1: [ 
    ['01.html', 2], 
    ] 
} 

tokens = %i[ 
    word1 
    word2 
    word3 
] 

doc_name = '01.html' 

tokens.each do |token| 
    if !invindex.include?(token) 
    invindex[token] = [[doc_name, 1]] #adds the word to the hash with the doc name and occurrence of 1 
    else 
    invindex[token].each do |list| 
     if list[0] == doc_name 
     list[1] += 1 #adds one to the occurrence with the same doc_name 
     else 
     invindex[token] << [doc_name, 1] #this SHOULD append the doc name and initial occurrence inside the word's value list since the word is already in the hash 
     end 
    end 
    end 

end 

p invindex 

--output:-- 
{:word1=>[["01.html", 3]], :word2=>[["01.html", 1]], :word3=>[["01.html", 1]]} 

但是,仍然是一個問題,這是由於這樣的事實,你改變了這一切,你都在加緊通過陣列 - 一大禁忌在計算機編程:

invindex[token].each do |list| 
     if list[0] == doc_name 
     list[1] += 1 #adds one to the occurrence with the same doc_name 
     else 
     invindex[token] << [doc_name, 1] #***PROBLEM*** 

看看會發生什麼:

invindex = { 
    word1: [ 
    ['01.html', 2], 
    ] 
} 

tokens = %i[ 
    word1 
    word2 
    word3 
] 

%w[ 01.html 02.html].each do |doc_name| 

    tokens.each do |token| 
    if !invindex.include?(token) 
     invindex[token] = [[doc_name, 1]] #adds the word to the hash with the doc name and occurrence of 1 
    else 
     invindex[token].each do |list| 
     if list[0] == doc_name 
      list[1] += 1 #adds one to the occurrence with the same doc_name 
     else 
      invindex[token] << [doc_name, 1] #this SHOULD append the doc name and initial occurrence inside the word's value list since the word is already in the hash 
     end 
     end 
    end 

    end 
end 

p invindex 

--output:-- 
{:word1=>[["01.html", 3], ["02.html", 2]], :word2=>[["01.html", 1], ["02.html", 2]], :word3=>[["01.html", 1], ["02.html", 2]]} 

問題1:每次檢查的子陣列都不包含doc_name時,您不希望插入[doc_name, 1] - 在所有子陣列檢查完成後您只想插入[doc_name, 1],並且doc_name不是找到。如果使用開始的哈希運行上面的示例:

invindex = { 
    word1: [ 
    ['01.html', 2], 
    ['02.html', 7], 
    ] 
} 

...您會看到輸出更糟。

問題2:追加[doc_name, 1]的陣列,而你是通過數組步進意味着[doc-name, 1]將進行檢查,也當循環獲取到數組的結尾 - 然後你的循環將增加其計數到2.規則是:不要更改你正在通過的數組,因爲不好的事情會發生。

+0

謝謝你的幫助。我接受了您的建議,並在我重複完成時避免編輯陣列。我最終創建了一個「包含」變量,如果其中一個子數組具有doc_name,它將從False更改爲True。在迭代結束時,如果contains仍然是False,那麼我會在最後添加新的子列表。 我是Ruby的新手,一般編程,我一直在拋棄深刻的一面,清楚我有很多東西要學,所以謝謝! – jblittle

1

你確實需要一個包含數組數組的散列嗎?

這可以用一個嵌套的哈希值進行更好的描述

invindex = { 
    "word" => { '01.html' => 2, '02.html' => 7, '03.html' => 4 }, 
    "other" => { '01.html' => 1, '02.html' => 17, '04.html' => 4 } 
} 

可以通過現在使用類似

invindex = Hash.new { |h,k| h[k] = Hash.new {|hh,kk| hh[kk] = 0} } 
tokens.each do |token| 
    invindex[token][doc_name] += 1 
end 

散列工廠,如果你絕對需要有你提到的格式很容易填充你可以通過簡單的迭代從描述的invindex得到它

result = {} 
invindex.each {|k,v| result[k] = v.to_a } 
1

假設:

arr = %w| 01.html 02.html 03.html 02.html 03.html 03.html | 
    #=> ["01.html", "02.html", "03.html", "02.html", "03.html", "03.html"] 

是你的文件的索引中的給定字的數組。

h = arr.each_with_object(Hash.new(0)) { |s,h| h[s] += 1 } 
    #=> {"01.html"=>1, "02.html"=>2, "03.html"=>3} 

,然後將其轉換爲一個數組:

h.to_a 
    #=> [["01.html", 1], ["02.html", 2], ["03.html", 3]] 

,所以你可以寫:然後在哈希這個詞的價值是通過構建計數哈希給出

arr.each_with_object(Hash.new(0)) { |s,h| h[s] += 1 }.to_a 

Hash::new被給予默認值零。這意味着如果構造的散列h沒有密鑰sh[s]將返回零。在這種情況下:

h[s] += 1 
    #=> h[s] = h[s] + 1 
    #  = 0 + 1 = 1 

而當sarr相同的值傳遞給塊:

h[s] += 1 
    #=> h[s] = h[s] + 1 
    #  = 1 + 1 = 2 

您可以考慮它是否會更好地使每個字的價值索引散列h