【问题标题】:Cleanest way to create a Hash from an Array从数组创建哈希的最简洁方法
【发布时间】:2010-09-29 14:12:20
【问题描述】:

我似乎经常遇到这种情况。我需要使用数组中每个对象的属性作为键,从数组中构建一个哈希。

假设我需要一个示例使用 ActiveRecord 对象的哈希,这些对象由它们的 id 键控 常用方式:

ary = [collection of ActiveRecord objects]
hash = ary.inject({}) {|hash, obj| hash[obj.id] = obj }

另一种方式:

ary = [collection of ActiveRecord objects]
hash = Hash[*(ary.map {|obj| [obj.id, obj]}).flatten]

梦想之路: 我可以并且可能自己创建它,但是 Ruby 或 Rails 中是否有任何东西可以做到这一点?

ary = [collection of ActiveRecord objects]
hash = ary.to_hash &:id
#or at least
hash = ary.to_hash {|obj| obj.id}

【问题讨论】:

    标签: ruby-on-rails ruby arrays hash


    【解决方案1】:

    您可以自己将 to_hash 添加到 Array 中。

    class Array
      def to_hash(&block)
        Hash[*self.map {|e| [block.call(e), e] }.flatten]
      end
    end
    
    ary = [collection of ActiveRecord objects]
    ary.to_hash do |element|
      element.id
    end
    

    【讨论】:

      【解决方案2】:

      ActiveSupport 中已经有一个方法可以做到这一点。

      ['an array', 'of active record', 'objects'].index_by(&:id)
      

      为了记录,这里是实现:

      def index_by
        inject({}) do |accum, elem|
          accum[yield(elem)] = elem
          accum
        end
      end
      

      可以重构为(如果您迫切需要单行的话):

      def index_by
        inject({}) {|hash, elem| hash.merge!(yield(elem) => elem) }
      end
      

      【讨论】:

      • 我想如果你把merge改成merge!您将避免创建一堆您不需要的中间哈希。
      • 如果您要在应用程序的关键路径中多次使用它,您可能需要考虑使用 ary.index_by{|o| o.id} 而不是使用 symbol_to_proc。
      • index_by 似乎是 Ruby 的 group_by 的复制品。我错过了什么吗?
      • group_by 有一个数组作为值,而 index_by 假设每个键只有一个项目,因此值是单个项目,而不是数组。
      • ['an array', 'of active record', 'objects'].index_by(&:id) 失败并出现错误 NoMethodError: undefined method `id' for "an array":String using Rails 4.2.5 and Ruby 2.3.0
      【解决方案3】:

      安装Ruby Facets Gem 并使用他们的Array.to_h

      【讨论】:

      • 我不建议为简单方法添加依赖项
      【解决方案4】:

      最短的?

      # 'Region' is a sample class here
      # you can put 'self.to_hash' method into any class you like 
      
      class Region < ActiveRecord::Base
        def self.to_hash
          Hash[*all.map{ |x| [x.id, x] }.flatten]
        end
      end
      

      【讨论】:

        【解决方案5】:

        万一有人得到普通数组

        arr = ["banana", "apple"]
        Hash[arr.map.with_index.to_a]
         => {"banana"=>0, "apple"=>1}
        

        【讨论】:

          猜你喜欢
          • 2023-03-08
          • 2010-10-24
          • 1970-01-01
          • 2014-05-25
          • 1970-01-01
          • 1970-01-01
          • 2011-04-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多