2015-11-07 47 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