【问题标题】:How to assign an array of Hashes in a loop?如何在循环中分配哈希数组?
【发布时间】:2013-01-16 00:17:12
【问题描述】:

我正在尝试将 ActiveRecord 对象中的 MySQL 时间戳转换为另一种时间戳格式。我的方法接受一个 ActiveRecord 记录数组,并返回一个哈希数组,其中包含带时间戳的字段和格式化的时间戳:

def convert_mysql_timestamps(records)
    ary = []
    hash = {}
    records.each_with_index do |record, i|
      record.attributes.each do |field, value|
        if time_columns.include?(field) and value then
          hash[field] = value.strftime("%Y-%m-%dT%H:%M:%S%z")
        else
          hash[field] = value
        end
      end
      ary[i] = {}
      ary[i] = hash
    end
    ary
  end

但是,在ary[i] = hash 赋值中,所有ary 元素都被设置为散列。

有没有更好的方法来转换记录的时间戳字段? (我不需要将记录保存回数据库。)另外,我怎样才能让数组来捕获记录的每个单独的哈希表示?

输入:

[#<Vehicle id: 15001, approved_at: "2011-03-28 10:16:31", entry_date: "2011-03-28 10:16:31">, #<Vehicle id: 15002, approved_at: "2011-03-28 10:16:31", entry_date: "2011-03-28 10:16:31">]

期望的输出:

[{"id"=>15001, "approved_at"=>"2011-03-28T10:16:31-0700", "entry_date"=>"2011-03-28T10:16:31-0700"}, {"id"=>15002, "approved_at"=>"2011-03-28T10:16:31-0700", "entry_date"=>"2011-03-28T10:16:31-0700"}]

【问题讨论】:

  • 提供不起作用的代码无助于理解问题。不得不阅读这样的东西对读者来说简直是一种负担。提供示例输入和预期输出会更有帮助。
  • 一个示例初始数据集也会有所帮助。
  • 也许你的hash = {} 应该在你的each_with_index 块内。
  • 已添加输入和所需输出。
  • @mu 太短 - 你是对的。在 each_with_index 块内声明哈希修复了它。谢谢!如果您回复您的回复,我会检查它。

标签: ruby-on-rails ruby arrays hash


【解决方案1】:

问题是你正在创建一个哈希:

def convert_mysql_timestamps(records)
  ary = []
  hash = {}
  #...

然后尝试对每条记录重复使用。您可能希望每次 each_with_index 迭代都有一个新的哈希:

  def convert_mysql_timestamps(records)
    ary = []
    records.each_with_index do |record, i|
      hash = { }
      record.attributes.each do |field, value|
        #...
      end
      ary[i] = hash
    end
  end

【讨论】:

    【解决方案2】:

    您可以为此使用map - 当您想要以一种格式获取数组并以另一种格式生成相同大小的数组时,它始终是一个不错的选择。方法如下:

    def convert_mysql_timestamps(records)
      records.map do |record|
        Hash[records.attributes.map{|k, v| [k, convert_mysql_timestamp(v)] }]
      end
    end
    
    def convert_mysql_timestamp(field, value)
      return value unless time_columns.include?(field) && value
      value.strftime("%Y-%m-%dT%H:%M:%S%z")
    end
    

    它是这样工作的:

    • Hash[array_of_pairs] 将键值对数组(例如 [["foo", 2], ["bar", 3], ...])转换为类似 {"foo" =&gt; 2, "bar" =&gt; 3, ...} 的散列。

    • map 为集合中的每个项目调用其块,并将块的每个返回值收集到一个新数组中,然后返回。 Hash[...] 内部的attributes.map 创建键值对数组,外部records.map 将所有哈希收集到返回的数组中。

    我建议阅读Enumerable 中的方法,因为其中有很多类似map 的简洁内容。您会发现您几乎不必在循环中使用索引,尽管如果您来自另一种语言,并且到处都有for 循环,那么很难改掉这个习惯!

    【讨论】:

    • 安迪 - 感谢您的贡献。我喜欢你的“少即是多”的代码。我答应过我会把这个给穆太短,因为他第一个回应。
    • 没问题 - 即使你不接受它,如果它有帮助也欢迎你投票:)
    【解决方案3】:

    我不确定你的time_columns 是什么,但假设它们是Time 类,你可以像value.is_a?(Time) 这样简化部分。

    def convert_mysql_timestamps(records)
    
     records.collect do |record|
       # assuming records are from a Rails model, I am using #attributes 
       # to loop through all fields in a record 
                        # then inject values in this hash -> ({}), 
                        # which is in the block, named attributes
       record.attributes.inject({}) do |attributes, (column_name, value)|
         # if it is Time, convert it to iso8601 (slightly different from your format, 
         # but if this is also acceptable, your code can be simpler)
         attributes[column_name] = (value.is_a?(Time) ? value.iso8601 : value)
         attributes
       end
     end
    
    end
    

    【讨论】:

    • kukrt - 感谢您很好地改进了代码示例。效果很好!给mu这个太短了,因为他先回复了。
    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 2018-06-10
    • 2018-06-14
    相关资源
    最近更新 更多