2013-04-01 197 views
4

我在我的應用程序中的建設,我需要這樣的哈希幾個哈希參數:設置具有相同的價值,但不同的密鑰

{ 1 => [6,2,2], 2 => [7,4,5], (3..7) => [7,2,1] }

所以我想有鑰匙3相同的值, 4,5,6和7.
當然上面的例子不起作用,因爲Ruby是智能的,並設置散列鍵爲給定:它將範圍設置爲鍵:)所以我只能訪問我的價值爲my_hash[(3..7)]my_hash[3]my_hash[4]等沒有。
當然,我可以在哈希之外進行檢查或構建來完成我所需要的操作,但是我很好奇,如果可以在不使用哈希聲明之外的任何循環的情況下設置像這樣的哈希?如果不是,最優雅的是什麼?謝謝!

+1

你想要什麼不清楚?你想要什麼輸出?你有什麼投入? –

+0

@iAmRubuuu我認爲這很清楚,他們正在尋找一種方法來輕鬆初始化Hashes,而無需循環,他們可以指定一系列具有相同值的鍵。 –

+0

[如何引用哈希鍵中的值]的可能重複(http://stackoverflow.com/questions/8379814/how-to-reference-a-value-for-a-key-in-a-哈希) –

回答

4

這有什麼特別的錯嗎?

myhash = { 1 => [6,2,2], 2 => [7,4,5] } 
(3..7).each { |k| myhash[k] = [7,2,1] } 
+0

謝謝隊友!這是最性感的,這就是我將要使用的:) – konnigun

3

我不認爲有一種方法,使用文字哈希語法設置多個按鍵,或沒有一些反覆,但這裏有反覆做短的路:

irb(main):007:0> h = { 1 => [6,2,2], 2 => [7,4,5] }; (3..7).each {|n| h[n] = [7,2,1]}; h 
=> {1=>[6, 2, 2], 2=>[7, 4, 5], 3=>[7, 2, 1], 4=>[7, 2, 1], 5=>[7, 2, 1], 6=>[7, 2, 1], 7=>[7, 2, 1]} 

(注意尾隨; h只是上面顯示的目的)

5

你可以繼承Hash,使其更容易構建這樣的哈希值:

class RangedHash < Hash 
    def []=(key, val) 
    if key.is_a? Range 
     key.each do |k| 
     super k, val 
     end 
    else 
     super key, val 
    end 
    end 
end 

它與常規散列相同,除非使用Range鍵時,它會在Range中的每個點處設置給定值。

irb(main):014:0> h = RangedHash.new 
=> {} 
irb(main):015:0> h[(1..5)] = 42 
=> 42 
irb(main):016:0> h[1] 
=> 42 
irb(main):017:0> h[5] 
=> 42 
irb(main):018:0> h['hello'] = 24 
=> 24 
irb(main):019:0> h['hello'] 
=> 24 
+0

+1可能太快了。打敗我37秒! – DigitalRoss

+0

謝謝,這很好,我只需要在一個地方的功能,所以我不會專門爲它寫一個類^^但是如果我第二次需要它(我打賭我會)我會用你的實現: ) 謝謝! – konnigun

1

直接修補哈希,但在其他方面相同的思路Luke's...

class Hash 
    alias_method :orig_assign, '[]=' 
    def []= k, v 
    if k.is_a? Range 
     k.each { |i| orig_assign i, v } 
     v 
    else 
     orig_assign k, v 
    end 
    end 
end 

t = {} 
t[:what] = :ever 
t[3..7] = 123 
p t # => {5=>123, 6=>123, 7=>123, 3=>123, 4=>123, :what=>:ever} 
0

下面是一些方法:

h = { 1 => [6,2,2], 2 => [7,4,5], (3..7) => [7,2,1] } 

def my_hash(h,y) 
    h.keys.each do |x| 
    if (x.instance_of? Range) and (x.include? y) then 
     return p h[x] 
    end 
    end 
p h[y] 
end 

my_hash(h,2) 
my_hash(h,3) 
my_hash(h,1) 
my_hash(h,10) 
my_hash(h,5) 
my_hash(h,(3..7)) 

輸出:

[7, 4, 5] 
[7, 2, 1] 
[6, 2, 2] 
nil 
[7, 2, 1] 
[7, 2, 1] 
+0

**向下投票人:**爲什麼投下票?請解釋。在投票之前,SO清楚地向你顯示了一條信息,說明你的理由。你無權忽略這一點。 –

+0

降低選票費用,就像他們花費你一樣。很多人都會開車匆忙下來,他們太雞了*(說出爲什麼他們會倒下,當我知道我有一個很好的答案並得到低估時,比如在我的回答中,我認爲這是因爲他們太無知理解,所以不用擔心,只要有較高的好答案比率就可以了,並且從長遠來看,它會自行解決。 –

+0

@theTinMan你是對的!我給出的代碼,我已經測試過了但是不知道誰不會問我他/她的困惑,這是非常糟糕的做法,我給你的投票權 –

2

我不喜歡爲範圍內的每個可能條目創建單獨的鍵/值對。它根本無法擴展,特別是對於廣泛的範圍。考慮這個小範圍:

'a' .. 'zz' 

這將導致702個額外的鍵。嘗試('a'..'zz').to_a的樂趣。前進。我會等。

而不是創建密鑰,攔截查找。重用RangedHash類名稱:

class RangedHash < Hash 
    def [](key) 
    return self.fetch(key) if self.key? key 

    self.keys.select{ |k| k.is_a? Range }.each do |r_k| 
     return self.fetch(r_k) if r_k === key 
    end 

    nil 
    end 
end 

foo = RangedHash.new 
foo[1] = [6,2,2] 
foo[2] = [7,4,5] 
foo[3..7] = [7,2,1] 

此時foo樣子:用於測試的方法

{1=>[6, 2, 2], 2=>[7, 4, 5], 3..7=>[7, 2, 1]} 

require 'pp' 
3.upto(7) do |i| 
    pp foo[i] 
end 

,輸出:

[7, 2, 1] 
[7, 2, 1] 
[7, 2, 1] 
[7, 2, 1] 
[7, 2, 1] 

對於任何價值i在一個範圍內,輸出與該範圍相關的值。超出範圍但仍在散列中定義的值正常工作,對散列中不存在的鍵返回nil也是如此。而且,它保持儘可能小的散列。

這個問題或任何問題的解決方案的缺點是範圍可能重疊導致衝突的關鍵。在大多數提議的解決方案中,鍵會彼此跺腳,這可能最終會返回錯誤的值。這種方法不會這樣做,因爲它會直接衝突來覆蓋範圍鍵。

要解決這個問題,需要確定是否允許重疊,如果是,是否可以返回找到的第一個,或者是否存在確定「最佳擬合」的邏輯,即最小範圍完全適合或者其他一些標準。或者,如果價值相同,應該重疊加入一個更大的範圍?這是一個蠕蟲的罐頭。

相關問題