【问题标题】:Subtract two hashes in Ruby在 Ruby 中减去两个哈希值
【发布时间】:2014-07-08 21:21:59
【问题描述】:

可以修改hash 类,以便给定两个散列,创建一个新散列,其中只包含一个散列中存在但另一个散列中不存在的键?

例如:

h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10}

h2 = {"Cat" => 100, "Dog" => 5, "Bison" => 30}

h1.difference(h2) = {"Bird" => 2, "Snake" => 10}

可选地,difference 方法可以包含任何键/值对,这样键在两个哈希中都存在,但它们之间的值不同。

【问题讨论】:

    标签: ruby hash


    【解决方案1】:
    h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10}
    h2 = {"Cat" => 999, "Dog" => 5, "Bison" => 30}
    

    情况 1:将所有键/值对 k=>v 保留在 h1 中,而 k 中没有键 k 中的 h2

    这是一种方式:

    h1.dup.delete_if { |k,_| h2.key?(k) }
      #=> {"Bird"=>2, "Snake"=>10}
    

    这是另一个:

    class Array
      alias :spaceship :<=>
      def <=>(o)
        first <=> o.first
      end
    end
    
    (h1.to_a - h2.to_a).to_h
      #=> {"Bird"=>2, "Snake"=>10}
    
    class Array
      alias :<=> :spaceship
      remove_method(:spaceship)
    end
    

    案例2:保留h1中所有不在h2中的键/值对

    您只需要:

    (h1.to_a - h2.to_a).to_h
      #=> {"Cat"=>100, "Bird"=>2, "Snake"=>10}
    

    Array#to_h 是在 Ruby 2.0 中引入的。对于早期版本,请使用Hash[]

    【讨论】:

      【解决方案2】:

      使用reject 方法:

      class Hash
        def difference(other)
          reject do |k,v|
            other.has_key? k
          end
        end
      end
      

      仅在值相同的情况下拒绝键/值对(根据 mallanaga 的建议,通过对我已删除的原始答案的评论):

      class Hash
        def difference(other)
          reject do |k,v|
            other.has_key?(k) && other[k] == v
          end
        end
      end
      

      【讨论】:

      • 嗯,我没有意识到这是约定俗成的 - 一定是有点太快地浏览了 Eloquent Ruby 的那部分。
      • 好书,但奥尔森先生可能认为读者知道这一点。如果您喜欢这本书,请查看Metaprogramming Ruby
      • 有些读者可能认为reject 返回的是一个数组,而不是一个哈希值。确实,Enumerable#reject 返回一个数组,并且Hash 类包含Enumerable 模块,但Hash 也有方法Hash#reject,它返回一个散列并且优先于可枚举rejectselect 也一样。注意Hash#reject!Hash#select! 有方法,但Enumerable 模块中没有对应的! 方法。
      【解决方案3】:

      你可以这样做:

      h2.each_with_object(h1.dup){|(k, v), h| h.delete(k)}
      

      【讨论】:

      • each_with_object 方法直到 Ruby 1.9 才引入,我怀疑这比我建议的 h1.reject{|k,v| h2.has_key? k} 更快。
      【解决方案4】:

      尝试使用 hashdiff gem。

      diff=HashDiff.diff(h1,h2)
      

      【讨论】:

      • 您能否提供更多详细信息(和链接)?从 rubydoc.info/gems/hashdiff/0.2.2 看来,这似乎在做一些不同的事情。一方面,它返回一个列表列表,其中每个内部列表包含三个元素,而不是一个新的散列。此外,如果h2 包含不在h1 中的元素,则这些元素将被表示——这不是散列减法操作的情况。
      【解决方案5】:

      对于深度嵌套,您可以添加一些递归,例如(未经测试)

      class Hash
        def -(h2)
          raise ArgumentError unless h2.is_a?(Hash)
          h1 = dup
          h1.delete_if do |k, v|
            if v.is_a?(Hash) && h2[k].is_a?(Hash)
              h1[k] = v - h2[k]
              h1[k].blank?
            else
              h2[k] == v
            end
          end
         end
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-28
        • 2014-04-09
        • 2013-07-21
        • 2017-12-18
        相关资源
        最近更新 更多