2010-03-21 36 views
5

我有代碼:類型錯誤:不能轉換成字符串整數

class Scene 
    def initialize(number) 
    @number = number 
    end 
    attr_reader :number 
end 

scenes = [Scene.new("one"), Scene.new("one"), Scene.new("two"), Scene.new("one")] 

groups = scenes.inject({}) do |new_hash, scene| 
    new_hash[scene.number] = [] if new_hash[scene.number].nil? 
    new_hash[scene.number] << scene 
end 

當我空空它,我得到錯誤:

freq.rb:11:in `[]': can't convert String into Integer (TypeError) 
     from freq.rb:11:in `block in <main>' 
     from freq.rb:10:in `each' 
     from freq.rb:10:in `inject' 
     from freq.rb:10:in `<main>' 

如果我改變場景:

scenes = [Scene.new(1), Scene.new(1), Scene.new(2), Scene.new(1)] 

問題消失。

爲什麼我會在第一種情況下收到錯誤消息?爲什麼Ruby決定將scene.number從String轉換爲Integer?

而一個關於「注射」的方法更多的問題。當Ruby初始化'new_hash'變量時,Ruby如何知道這個變量的類型?

+1

btw:你可以通過使用'groups = scenes.group_by(&:number)'而不是注入來更輕鬆地做到你想要的。 – sepp2k 2010-03-21 11:54:15

+0

的new_hash變量與注入的值進行初始化(記住:這是一個摺疊操作在該蓄壓有一個初始值) – hurikhan77 2010-03-21 12:27:30

回答

6

Z.E.D.的權利。舉例來說,請參閱Jay Fields' Thoughts: Ruby: inject以獲得對inject的很好的解釋。

如前所述,您的塊返回一個數組。因此,在|new_hash, scene|new_hash最終被該數組。當Ruby試圖找到數組索引'one'時,它會拋出錯誤,因爲'one'是一個字符串,而不是一個整數。

所有你需要做的是回到new_hash爲Z.E.D.結果顯示,你會得到這樣的事情:

{ 
    "two" => [ 
    #<Scene:0x101836470 @number="two"> 
    ], 
    "one" => [ 
    #<Scene:0x101836510 @number="one">, 
    #<Scene:0x1018364c0 @number="one">, 
    #<Scene:0x101836420 @number="one"> 
    ] 
} 
10

嘗試:

 
groups = scenes.inject({}) do |new_hash, scene| 
    new_hash[scene.number] = [] if new_hash[scene.number].nil? 
    new_hash[scene.number] << scene 
    new_hash 
end 

紅寶石需要()傳遞到注射空哈希和套new_hash了這一點。塊結束時,返回值在下一次通過時用於初始化new_hash,即new_hash不斷累加塊的結果。

在你原來的代碼中,你並沒有返回散列,而是一個數組(new_hash [scene.number]是一個數組),並且通過Ruby的下一個循環抱怨,因爲new_hash [scene.number]試圖查找到數組與字符串值,因此你得到的錯誤。

+1

爲什麼這個downvoted?這是正確的答案。 – sepp2k 2010-03-21 11:12:25

+0

,因爲它失敗 – shingara 2010-03-21 11:34:47

+0

@shingara:不,它不會失敗。他的代碼無誤地運行並返回預期結果。 – sepp2k 2010-03-21 11:49:39

0

此外,來解釋「紅寶石怎麼能知道這個變量的類型,」它試圖「字符串轉換成整數」,爲什麼你可能要修改:Ruby variables and dynamic typing

2

爲什麼不使用group_by這可能正是你嘗試accomblish什麼?

groups = scenes.group_by(&:number) 
# => {"two"=>[#<Scene:0xb728ade0 @number="two">], 
#  "one"=> 
#  [#<Scene:0xb728ae30 @number="one">, 
#  #<Scene:0xb728ae08 @number="one">, 
#  #<Scene:0xb728ada4 @number="one">]} 

inject是一種摺疊操作,並不完全是你想要的。至少使用這種方法很麻煩。 merge如果您想在合併或分組過程中應用某種算法,則可能適合使用塊。

0

我知道一個答案是接受了這個問題,但我不禁張貼我的答案。

groups = scenes.inject({}) { |nh, s| nh.tap {|h| (h[s.number] ||= []) << s } } 
相關問題