【问题标题】:Ruby hash with multiple keys pointing to the same value具有多个指向相同值的键的 Ruby 哈希
【发布时间】:2013-04-09 22:51:46
【问题描述】:

我正在寻找一种方法,我会说哈希中的同义词键。

我希望多个键指向同一个值,因此我可以通过这些键中的任何一个读/写一个值。

例如,它应该是这样工作的(假设 :foo 和 :bar 是同义词)

hash[:foo] = "foo"
hash[:bar] = "bar"
puts hash[:foo] # => "bar"

更新 1

让我补充几个细节。我需要这些同义词的主要原因是,我从外部源接收键,这是我无法控制的,但实际上可以将多个键与同一个值关联。

【问题讨论】:

  • 您可以添加更多上下文吗?你想达到什么目标?
  • 你为什么要这样做?如果您希望 hash[:foo] 返回“bar”,您可以创建它。哈希[:foo] = "bar",哈希[:bar] = "foo"。这个问题对我来说毫无意义!
  • @shime & sbagdat:请看更新。

标签: ruby


【解决方案1】:

重新思考您的数据结构

根据您想要访问数据的方式,您可以通过将键或值设为数组来使它们成为同义词。无论哪种方式,您都需要做更多的工作来解析同义词而不是它们共享的定义词。

作为定义的键

例如,您可以使用键作为同义词的定义。

# Create your synonyms.
hash = {}
hash['foo'] = %w[foo bar]
hash
# => {"foo"=>["foo", "bar"]}

# Update the "definition" of your synonyms.
hash['baz'] = hash.delete('foo')
hash
# => {"baz"=>["foo", "bar"]}

作为定义的值

您也可以反转此结构,并改为将您的键数组设为同义词。例如:

hash = {["foo", "bar"]=>"foo"}
hash[hash.rassoc('foo').first] = 'baz'
=> {["foo", "bar"]=>"baz"}

【讨论】:

    【解决方案2】:

    您可以继承哈希并覆盖 [][]=

    class AliasedHash < Hash
      def initialize(*args)
        super
        @aliases = {}
      end
    
      def alias(from,to)
        @aliases[from] = to
        self
      end
    
      def [](key)
        super(alias_of(key))
      end
    
      def []=(key,value)
        super(alias_of(key), value)
      end
    
      private
      def alias_of(key)
        @aliases.fetch(key,key)
      end
    end
    
    ah = AliasedHash.new.alias(:bar,:foo)
    
    ah[:foo] = 123
    ah[:bar] # => 123
    ah[:bar] = 456
    ah[:foo] # => 456
    

    【讨论】:

    • 不要扩展核心 ruby​​ 类,使用委托!
    【解决方案3】:

    只要将相同的对象分配给两个键,您就完全可以做到。

    variable_a = 'a'
    hash = {foo: variable_a, bar: variable_a}
    
    puts hash[:foo] #=> 'a'
    hash[:bar].succ!
    puts hash[:foo] #=> 'b'
    

    这是因为hash[:foo]hash[:bar] 都通过variable_a 引用了a 的同一个实例。但是,如果您使用赋值 hash = {foo: 'a', bar: 'a'},这将不起作用,因为在这种情况下,:foo:bar 指的是不同的实例变量。

    【讨论】:

    • 只要所有值更改仅限于引用的对象变异方法(如succ!replace),此方法就可以工作。一旦有人通过[]= 赋值设置了一个别名值,别名就会被破坏。
    • @Gavin Miller:有趣的想法,但相当有限,因为我将一直使用引用(而不是值)
    【解决方案4】:

    你原来的帖子的答案是:

    hash[:foo] = hash[:bar]
    

    hash[:foo].__id__ == hash[:bar].__id__it
    
    只要值是参考值 (String, Array ...) ,

    就会成立。


    更新 1 的答案可能是:

    input.reduce({ :k => {}, :v => {} }) { |t, (k, v)| 
            t[:k][t[:v][v] || k] = v;
            t[:v][v] = k;
            t
        }[:k]
    

    其中 «input» 是输入数据的抽象枚举器(或数组),因为它来自 [key, value]+,«:k» 您的结果,«:v» 是用于查找目的的反向哈希如果其值已存在,则为键。

    【讨论】:

    • 操作,将t[:k][t[:v][v] || k] = v; 替换为t[:k][k] = t[:k][t[:v][v]] || v;
    猜你喜欢
    • 2014-09-14
    • 2014-06-05
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-13
    • 2011-10-04
    相关资源
    最近更新 更多