【问题标题】:Sequentially parse array to hash in Ruby在Ruby中按顺序解析数组以散列
【发布时间】:2013-07-30 15:28:25
【问题描述】:

我有一个如下所示的数组:

array = [
  "timestamp 1",
  "data 1",
  "data 2",
  "data 3",
  "timestamp 2",
  "data "1",
  "timestamp 3",
  ".." 
]
  etc

我想遍历我的数组,并将其转换为如下所示的哈希数据结构:

hash = { 
  "timestamp 1" => [ "data 1", " data 2", "data 3" ],
  "timestamp 2" => [ "data 1" ],
}

我想不出一个好的“红宝石”方法。我正在遍历数组,但我似乎完全不知道如何跟踪我所在的位置,并根据需要分配给哈希。

# Let's comb through the array, and map the time value to the subsequent lines beneath
array.each do |e|
  if timestamp?(e)
    hash["#{e}"] == nil
  else
    # last time stamp here => e
end

编辑:这是时间戳?方法

def timestamp?(string)
  begin
    return true if string =~ /[a-zA-z][a-z][a-z]\s[a-zA-z][a-z][a-z]\s\d\d\s\d\d:\d\d:\d\d\s\d\d\d\d/
    false
  rescue => msg
    puts "Error in timestamp? => #{msg}"
    exit
  end
end

【问题讨论】:

  • timestamp? 是做什么的?
  • 只是一个正则表达式确定它是否是有效时间戳的函数。我将使用该功能更新帖子。
  • 您的 array 不是有效的 Ruby 对象。检查第七行。
  • 明白了..我只是表明数组会这样继续下去。
  • 不,你似乎不明白。检查第七行。

标签: ruby


【解决方案1】:
array = [
  "timestamp 1",
  "data 1",
  "data 2",
  "data 3",
  "timestamp 2",
  "data 1",
  "timestamp 3",
  "data 2" 
]

hsh = {}
ary = []

array.each do |line|
  if line.start_with?("timestamp")
    ary = Array.new
    hsh[line] = ary
  else 
    ary << line
  end
end

puts hsh.inspect

【讨论】:

  • 我非常看重可读性。感谢您从人群中挑选出我的。
【解决方案2】:

我会这样做:

array = [
  "timestamp 1",
  "data 1",
  "data 2",
  "data 3",
  "timestamp 2",
  "data 1", 
]

Hash[array.slice_before{|i| i.include? 'timestamp'}.map{|a| [a.first,a[1..-1]]}]
# => {"timestamp 1"=>["data 1", "data 2", "data 3"], "timestamp 2"=>["data 1"]}

【讨论】:

    【解决方案3】:
    Hash[array.slice_before{|e| e.start_with?("timestamp ")}.map{|k, *v| [k, v]}]
    

    输出

    {
      "timestamp 1" => [
        "data 1",
        "data 2",
        "data 3"
      ],
      "timestamp 2" => ["data 1"],
      "timestamp 3" => [".."]
    }
    

    【讨论】:

      【解决方案4】:

      您可以使用外部变量跟踪最后一个哈希键。它将在所有迭代中持续存在:

      h = {}
      last_group = nil
      array.each do |e|
        if timestamp?(e)
          array[e] = []
          last_group = e
        else
          h[last_group] << e
        end
      end
      

      【讨论】:

        【解决方案5】:
        last_timestamp = nil
        array.reduce(Hash.new(){|hsh,k| hsh[k]=[]}) do |hsh, m|
          if m =~ /timestamp/
            last_timestamp = m
          else
            hsh[last_timestamp] << m
          end
          hsh
        end
        

        【讨论】:

          【解决方案6】:
          hash = (Hash.new { |this, key| this[key] = [] } ).tap do |hash|
            current_timestamp = nil
            array.each do |element|
              current_timestamp = element if timestamp? element
              hash[current_timestamp] << element unless timestamp? element
            end
          end
          

          使用外部变量来跟踪当前时间戳,但将其包装在闭包中以避免污染命名空间。

          【讨论】:

            【解决方案7】:

            我知道这已经得到解答,但是有很多方法可以做到这一点。

            我更喜欢这两种方式,它们可能不快但我觉得它们可读:

            my_hash = Hash.new
            array.slice_before(/timestamp/).each do |array|
              key, *values = array
              my_hash[key] = values
            end
            

            one_liner = Hash[array.slice_before(/timestamp/).map{|x|[x.shift, x]}]
            

            【讨论】:

              猜你喜欢
              • 2016-07-25
              • 1970-01-01
              • 1970-01-01
              • 2011-05-01
              • 2014-05-19
              • 2020-05-29
              • 2012-06-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多