【问题标题】:How to make dynamic multi-dimensional array in ruby?如何在 ruby​​ 中制作动态多维数组?
【发布时间】:2010-11-17 01:45:59
【问题描述】:

我有一个关于多维数组的 ruby​​ 初学者问题。

我想按年和月对条目进行排序。所以我想创建一个包含年 -> 月 -> 月条目的多维数组

所以数组会是这样的:

2009 ->
       08
          -> Entry 1
          -> Entry 2
       09
          -> Entry 3
2007 ->
       10
          -> Entry 5

现在我有:

@years = []
@entries.each do |entry|
    timeobj = Time.parse(entry.created_at.to_s)
    year = timeobj.strftime("%Y").to_i
    month = timeobj.strftime("%m").to_i
    tmparr = []
    tmparr << {month=>entry}
    @years.push(year)
    @years << tmparr
end

但当我尝试遍历 years 数组时,我得到:“2009:Fixnum 的未定义方法 `each'”

也试过了:

@years = []
@entries.each do |entry|
    timeobj = Time.parse(entry.created_at.to_s)
    year = timeobj.strftime("%Y").to_i
    month = timeobj.strftime("%m").to_i
    @years[year][month] << entry
end

【问题讨论】:

    标签: ruby arrays multidimensional-array


    【解决方案1】:

    您收到错误是因为FixNum(即一个数字)被推送到数组中,位于读取@years.push(year) 的行中。

    您使用数组开始的方法有点缺陷;数组非常适合保存有序的项目列表。在您的情况下,您有一个从键到值的映射,这对于哈希来说是完美的。

    在第一级,键是年份,值是哈希值。第二级的散列包含月份的键和条目数组的值。

    在这种情况下,您的代码的典型输出将类似于(基于您的示例):

    { 2009 => { 8 => [Entry1, Entry2], 9 => [Entry3] }, 2007 => { 10 => [Entry5] }}
    

    但请注意,年和月的顺序并不能保证是任何特定的顺序。解决方案通常是在您想要访问它们时订购密钥。现在,可以生成这样一个输出的代码(根据您的代码布局,虽然可以制作很多 rubier):

    @years = {}
    @entries.each do |entry|
      timeobj = Time.parse(entry.created_at.to_s)
      year = timeobj.strftime("%Y").to_i
      month = timeobj.strftime("%m").to_i
      @years[year] ||= {} # Create a sub-hash unless it already exists
      @years[year][month] ||= []
      @years[year][month] << entry
    end
    

    【讨论】:

    • 感谢您的启发。
    • 不客气。查看 Michael_Sepcot 的回答,了解如何以更 rubyish 的方式进行操作。
    • 谢谢!终于明白了
    【解决方案2】:

    group_bys 和map 的组合可以在一行中得到嵌套数组结构:

    @entries.group_by {|entry| entry.created_at.year }.map { |year, entries| [year, entries.group_by {|entry| entry.created_at.month }] }
    

    【讨论】:

    • 不是 group_by 是 rails 的补充,不是普通的老红宝石吗?
    • 啊 - 我在 Ruby 1.8.6 上尝试过。
    【解决方案3】:

    我使用的是哈希表而不是数组,因为我认为这里可能更有意义。但是,如果您愿意,改回使用数组是相当简单的。

    entries = [
        [2009, 8, 1],
        [2009, 8, 2],
        [2009, 9, 3],
        [2007, 10, 5]
    ]
    
    years = Hash.new
    entries.each { |e|
        year = e[0]
        month = e[1]
        entry = e[2]
    
        # Add to years array
        years[year] ||= Hash.new
        years[year][month] ||= Array.new
        years[year][month] << entry
    }
    
    puts years.inspect
    

    输出为:{2007=&gt;{10=&gt;[5]}, 2009=&gt;{8=&gt;[1, 2], 9=&gt;[3]}}

    【讨论】:

      【解决方案4】:
      # create a hash of hashes of array
      @years = Hash.new do |h,k|
        h[k] = Hash.new do |sh, sk|
          sh[sk] = []
        end
      end
      
      @entries.each do |entry|
        timeobj = Time.parse(entry.created_at.to_s)
        year = timeobj.year
        month = timeobj.month
        @years[year][month] << entry
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-17
        • 2011-08-29
        • 1970-01-01
        • 1970-01-01
        • 2017-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多