【问题标题】:Ruby: Appending hashes to an array in an each loopRuby:在每个循环中将散列附加到数组
【发布时间】:2014-06-12 16:53:43
【问题描述】:

我有一个称为间隔的数组。我希望从中构建一个哈希数组,为每个哈希添加两个键/值对(start_ts 和 stop_ts)。

require 'date'
date = '2014-06-12'
totalhash = Hash.new
totalarray = Array.new
payload2 = Array.new
totals = Array.new

intervals = [["Current", 0, 9999],
             ["1 to 4", -4, -1],
             ["5 to 15", -15, -5],
             ["16 to 30", -30, -16],
             ["31 to 60", -60, -31],
             ["61 to 90", -90, -61],
             ["91+", -9999, -91]]

intervals.each do |int|
    label, start, stop = int
    # Parse date and then convert to UNIX epoch (.to_time.to_i chain)
    start_ts = (Date.parse("#{date}") + start).to_time.to_i
    stop_ts = (Date.parse("#{date}") + stop).to_time.to_i

    totalhash[:label]             = label
    totalhash[:start]             = start
    totalhash[:stop]              = stop
    totalhash[:start_ts]          = start_ts
    totalhash[:stop_ts]           = stop_ts

    totalarray << totalhash
    totals = totalarray.reduce Hash.new, :merge
    puts totals
    puts 'totals size: ' + totals.size.to_s
end

最终结果应该是一个由七个哈希组成的数组。目前,数组 totalarray 似乎在每次传递时都会被覆盖,而不是被附加到。

我做错了什么。谢谢。

【问题讨论】:

  • 你是如何运行这段代码的?它有太多语法错误..
  • @ArupRakshit 我只看到一个语法错误:intervals.each do |int| dodo 两次)。
  • 我添加了 require 'date' 并删除了有问题的第二个 do。对此感到抱歉。
  • @Jordan 如果你运行,你会得到另一个,使用 OP 之前的代码。但在那之后,我没有运行它..
  • 您能解释一下totals 的含义吗?

标签: ruby arrays hash


【解决方案1】:

如果您想从数组中获得 1 对 1 的输出,请使用 map。它减少了对所有这些中间变量的需求。

# Parse date outside the loop as per @Uri's comment
day = Date.parse(date)

t = intervals.map do |interval|
      label, start, stop = interval
      {
        label:    label,
        start:    start,
        stop:     stop,
        start_ts: (day + start).to_time.to_i,
        stop_ts:  (day + stop).to_time.to_i
      }
    end

这会产生您想要的七哈希数组。

至于您得到的单个哈希输出:您的reduce 行是罪魁祸首。我不确定你想在那里做什么。

【讨论】:

  • 这些都是很好的答案,但我接受了这一点,因为这对我来说是最清楚的。谢谢,马克。
  • 好点@UriAgassi,我已合并您的评论。谢谢。
【解决方案2】:

这个:

totalarray << totalhash

不复制totalhash,它只是将引用附加到totalarray 的末尾。这么说会更有意义:

totalarray << {
  # build the Hash inline right here
}

您的代码最终以intervals.length 引用totalarray 中完全相同的哈希值结束。然后你的 reduce 将该哈希合并到自身中,这没有任何用处。实际上,即使正确构建了 totalarray,您的 totals = totalarray.reduce Hash.new, :merge 也没有任何用处,您可以只说 totals = totalarray.last 并得到相同的结果。

【讨论】:

    【解决方案3】:

    我通常是这样做的:

    myArray = [['cow','moo'],['dog','woof'],['duck','quack'],['fox','?']]
    
    myArray.collect! do |animal|
        animal = {animal[0]=>animal[1]}
    end
    
    puts myArray.inspect
    

    我对@9​​87654322@ 或inject不够熟悉,无法在此处评论您的使用。但这是您原始代码的编辑版本,我认为它可以满足您的需求:

    require 'date'
    date = '2014-06-12'
    #totalhash = Hash.new
    totalarray = Array.new
    payload2 = Array.new
    totals = Array.new
    
    intervals = [["Current", 0, 9999],
             ["1 to 4", -4, -1],
             ["5 to 15", -15, -5],
             ["16 to 30", -30, -16],
             ["31 to 60", -60, -31],
             ["61 to 90", -90, -61],
             ["91+", -9999, -91]]
    
    intervals.each do |int|
        totalhash = Hash.new   #moved your hash creation here, in the iteration
        label, start, stop = int
        # Parse date and then convert to UNIX epoch (.to_time.to_i chain)
        start_ts = (Date.parse("#{date}") + start).to_time.to_i
        stop_ts = (Date.parse("#{date}") + stop).to_time.to_i
    
        totalhash[:label]             = label
        totalhash[:start]             = start
        totalhash[:stop]              = stop
        totalhash[:start_ts]          = start_ts
        totalhash[:stop_ts]           = stop_ts
    
        totalarray << totalhash
        #totals = totalarray.reduce Hash.new, :merge
        #puts totals
        #puts 'totals size: ' + totals.size.to_s
    end
    
    puts totalarray.inspect #see the array object as is using 'inspect'
    

    ~

    【讨论】:

      【解决方案4】:

      我建议您考虑更改数据结构。我认为在每个哈希中包含自纪元以来的计算时间是不明智的。相反,只需使用辅助方法根据需要计算这些值:

      require 'date'
      
      date = Date.parse('2014-06-12')
        #=> #<Date: 2014-06-12 ((2456821j,0s,0n),+0s,2299161j)>
      
      def start_stop_to_time(d, date)
        (date + d).to_time.to_i
      end  
      

      例如,

      start_stop_to_time(-4, date) #=> 1402210800
      

      total_array 将是:

      total_array = [[:label, :start, :stop]].product(intervals)
                                             .map { |k,v| k.zip(v).to_h }
        #=> [{:label=> "Current", :start=>    0, :stop=>9999},
        #    {:label=>  "1 to 4", :start=>   -4, :stop=>  -1},
        #    {:label=> "5 to 15", :start=>  -15, :stop=>  -5},
        #    {:label=>"16 to 30", :start=>  -30, :stop=> -16},
        #    {:label=>"31 to 60", :start=>  -60, :stop=> -31},
        #    {:label=>"61 to 90", :start=>  -90, :stop=> -61},
        #    {:label=>     "91+", :start=>-9999, :stop=> -91}]
      

      我不明白totals的目的,所以我不能对此发表评论。

      【讨论】:

        猜你喜欢
        • 2017-09-23
        • 2013-11-14
        • 2019-03-03
        • 1970-01-01
        • 1970-01-01
        • 2020-09-14
        • 1970-01-01
        • 2012-09-22
        • 1970-01-01
        相关资源
        最近更新 更多