2013-04-01 144 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也是如此。而且,它保持尽可能小的散列。

这个问题或任何问题的解决方案的缺点是范围可能重叠导致冲突的关键。在大多数提议的解决方案中,键会彼此跺脚,这可能最终会返回错误的值。这种方法不会这样做,因为它会直接冲突来覆盖范围键。

要解决这个问题,需要确定是否允许重叠,如果是,是否可以返回找到的第一个,或者是否存在确定“最佳拟合”的逻辑,即最小范围完全适合或者其他一些标准。或者,如果价值相同,应该重叠加入一个更大的范围?这是一个蠕虫的罐头。

相关问题