Ruby:在每个循环中将哈希附加到数组中

时间:2014-06-12 16:53:43

标签: ruby arrays hash

我有一个名为interval的数组。我希望从中构建一个哈希数组,为每个哈希(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似乎在每次传递时被覆盖而不是被附加到。

我做错了什么。感谢。

4 个答案:

答案 0 :(得分: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行是罪魁祸首。我不确定你在那里做什么。

答案 1 :(得分:0)

此:

totalarray << totalhash

不会复制totalhash,它只会附加对totalarray末尾的引用。说:

更有意义
totalarray << {
  # build the Hash inline right here
}

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

答案 2 :(得分:0)

我通常会这样做:

myArray = [['cow','moo'],['dog','woof'],['duck','quack'],['fox','?']]

myArray.collect! do |animal|
    animal = {animal[0]=>animal[1]}
end

puts myArray.inspect

我不熟悉reduceinject来评论您在此处的使用情况。但是这里是您原始代码的编辑版本,我认为可以满足您的需求:

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'

答案 3 :(得分:0)

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

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的目的,所以我不能对此发表评论。