在Ruby Hash中搜索匹配值然后更改该值的键值对的最佳方法是什么?

时间:2015-05-06 01:37:52

标签: ruby

简单说明我的故障是这样的: 1.查找包含“选项”值的哈希 2.提示用户应该选择“选项”的值 3.将“选项”更改为用户想要的值(11或1)

我正在构建一个Blackjack游戏以更好地理解Ruby,并且我试图让用户能够从“手”中切换出值。我将牌组存储为包含牌组的哈希,然后像这样得分值:D8 => 8这是八颗钻石价值八分。 Aces,因为它们可以是1或11,就像这样存储:: SA => “选项。”

我希望能够提示用户输入值或者这是当前代码的一部分:

def checkAce
    if @player_hand.has_value?("option")

        puts "What do you want your aces to be worth? 11 or 1"

        ace_value = gets.chomp
        aces = @player_hand.find {|k, v| @player_hand[k] == "option"}

        if ace_value == "1" || ace_value == "11"
            aces.each { |k, v| aces[k] = ace_value }
        else 
            checkAce
        end 

        # merge back into hand 
        @player_hand.merge!(aces)

    else
        puts "No aces, so on to the main event." 
    end 
end

但是这段代码不起作用:首先,ace_value给了我一个类型错误,说符号不能被强制转换为整数。第二,@ player_hand.merge!(aces)找不到方法。有什么建议吗?

3 个答案:

答案 0 :(得分:1)

您的代码出现错误:

aces = @player_hand.find {|k, v| @player_hand[k] == "option"}

根据documentation,find返回第一个匹配值,而不是每个匹配值。你可能想要的是#find_all

例如:

hand = { a: 1, b: 2, c: 'option', d: 'option' }
hand.find { |_, v| v == 'option' } # => [:c, "option"]
hand.find_all { |_, v| v == 'option' } # => [[:c, "option"], [:d, "option"]]

您还会注意到,返回的内容不是哈希值,而是数组。您可以使用Hash[ [ [key, value], ... ] ]来获取哈希值。

例如:

Hash[[:c, "option"], [:d, "option"]] # => {[:c, "option"]=>[:d, "option"]}

因此,将它们放在一起,您可以使用以下内容提取哈希的相关部分:

hand = { a: 1, b: 2, c: 'option', d: 'option' }
aces = Hash[hand.find_all { |_, v| v == 'option' }]

其余代码按预期工作:

ace_value = 4
aces.each { |k, v| aces[k] = ace_value }
hand.merge!(aces) # => {:a=>1, :b=>2, :c=>4, :d=>4}

我真的不知道"最好的"更改与值匹配的哈希值的方法,但以下内容可能更少:

hand = { a: 1, b: 2, c: 'option', d: 'option' }
option_value = 'option'
ace_value = 4
hand.each do |k, v|
  if v == option_value
    hand[k] = ace_value
  end 
end # => {:a=>1, :b=>2, :c=>4, :d=>4}

你可以缩短为

hand.each { |k, v| hand[k] = ace_value if v == option_value }

如果你愿意的话。

答案 1 :(得分:1)

不一定非常有必要使用merge!。只需迭代哈希值即可更改相应的值。

def check_ace
  if @player_hand.has_value?("option")
    # get your input ace_value
    # ...
    if ["1", "11"].include?(ace_value)
      @player_hand.each_key { |k| @player_hand[k] = ace_value if @player_hand[k] == "option" }
    else
      check_ace
    end
  else
    puts "No aces, so on to the main event."  
  end
end

答案 2 :(得分:0)

因此,通过哈希映射在ruby中有点笨拙。这是基本的想法:

data = { a: 1, b: 2, c: 3 }

data = data.map do |k, v|
  if k == :b
    [k, 4]
  else
    [k, v]
  end
end.to_h

p(data)                         #=> {:a=>1, :b=>4, :c=>3}

如果有人知道一种更容易/更清洁的方式,我也会有兴趣看到它。

编辑:coderz有更好的答案,因为在这种情况下,您只需要更改一些值,而不是映射整个哈希值。