【问题标题】:Make hash keys map to the same value使哈希键映射到相同的值
【发布时间】:2015-12-26 05:49:30
【问题描述】:

这是我拥有的哈希:

color_hash = { sky: "blue", curtain: "blue", pavement: "black" }

有没有办法改变它以使两个键映射到相同的结果,如下所示:

color_hash = { sky or curtain: "blue", pavement: "black" }

我希望能够使用color_hash[:sky],它会打印blue,我可以使用color_hash[:curtain],它会打印blue

【问题讨论】:

  • 不清楚你的意思。你的意思是"sky or curtain": "blue"
  • 没有。我希望两个键映射到相同的结果
  • 它不是已经做你想做的了吗?
  • 说天空数据,窗帘数据是相关的。那么如果我改变它一次,我必须在两个不同的地方改变它。这就是为什么我想要两个键映射到同一个地方,所以我只需要更改一次值。
  • 它已经做了你想要的。它将为 :sky 和 ​​:curtain 返回“蓝色”

标签: ruby hash key mapping


【解决方案1】:

不,没有办法在 Ruby 中使用默认的哈希实现。见Is Ruby pass by reference or by value?。如果这是可能的,那么 Hash 上的 setter 方法 []= 必须以允许您通过引用传递的方式实现。

你可以用一些笨拙的语法和一个 Hash 的子类来实现这样的东西......这样的东西(只是一个警告,这仍然是错误的并且相当未经测试,但让你了解可能涉及的内容)

class FooHash < Hash
  attr_accessor :related

  def initialize(*args)
    @related = {}
    super
  end

  def []=(*args)
    raise ArgumentError.new("ArgumentError: wrong number of arguments (#{args.length} for 2)") unless args.length > 1
    value = args.pop
    keys = args.dup

    args.each_index do |index|
      key = keys.delete_at(index)
      if related[key]
        related[key].each do |related_key|
          continue if keys.include?(related_key)
          super(related_key, value)
        end
      else 
        related[key] = []
      end
      related[key] += keys
      related[key].uniq!
      keys.insert(index, key)
    end

    args.each do |arg|
      super(arg, value)
    end
  end
end

它可以让你做这样的事情:

1.9.3-p550 :036 > hsh = FooHash.new
 => {}
1.9.3-p550 :037 > hsh[:foo, :bar] = :baz
 => :baz
1.9.3-p550 :038 > hsh[:foo]
 => :baz
1.9.3-p550 :039 > hsh[:bar]
 => :baz
1.9.3-p550 :040 > hsh[:foo, :blah] = "baz2"
 => "baz2"
1.9.3-p550 :041 > hsh[:foo]
 => "baz2"
1.9.3-p550 :042 > hsh[:bar]
 => "baz2"
1.9.3-p550 :043 > hsh[:blah]
 => "baz2"

长话短说,尝试在 Ruby 中模仿指针操作有点恶心,不要这样做。

【讨论】:

  • 这样做也会破坏 Ruby 允许数组作为键的默认行为,这可能会产生一些非常惊人的副作用。
【解决方案2】:

即使我正确理解您想要做什么,请考虑使用不同的数据结构。

color_hash = { sky: "blue", pothole: "black", curtain: "blue",
               pavement: "black", roadblock: "red" }

你可以使用Enumerable#group_by:

color_hash.group_by(&:last).tap { |h| h.each_key { |k| h[k].map!(&:first) } }
  #=> {"blue"=>[:sky, :curtain], "black"=>[:pothole, :pavement],
  #    "red"=>[:roadblock]} 

Hash#update

color_hash.each_with_object({}) { |(k,v),h|
  h.update(v=>[k]) { |_,o,n| o+n } }
  #=> {"blue"=>[:sky, :curtain], "black"=>[:pothole, :pavement],
  #    "red"=>[:roadblock]}

这使用Hash#update(又名merge!)的形式,它使用一个块来确定在被合并的两个散列中存在的键的值。这里{ |_,o,n| o+n } 是那个块,其中(局部变量)_ 是键(而不是说k,告诉读者它没有在计算中使用),o(“旧” ) 是该键的哈希值 hn 是该键合并的哈希值。

【讨论】:

    【解决方案3】:

    也许试试这个。

      $someHashContainer = {:curtain => "Blue", :sky => "Blue"}
    
      def update_variables(value)
        $someHashContainer[:curtain] = value
        $someHashContainer[:sky] = $someHashContainer[:curtain]
      end
    
      puts $someHashContainer
    
      update_variables("Green")
      puts $someHashContainer
    
      $someHashContainer[:curtain] = "Red"
      puts $someHashContainer
    
      update_variables("Yellow")
      puts $someHashContainer
    
    
    '''
    OUTPUT:
    {:curtain=>"Blue", :sky=>"Blue"}
    {:curtain=>"Green", :sky=>"Green"}
    {:curtain=>"Red", :sky=>"Green"}
    {:curtain=>"Yellow", :sky=>"Yellow"}
    '''
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-13
      • 1970-01-01
      • 2015-09-08
      • 1970-01-01
      • 1970-01-01
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多