如何在ruby中制作动态多维数组?

时间:2009-08-05 15:48:26

标签: ruby arrays multidimensional-array

我有一个关于多维数组的初学红宝石问题。

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

所以数组就像:

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

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

也试过:

@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

4 个答案:

答案 0 :(得分:11)

您收到错误是因为FixNum(即数字)被推送到数组上的@years.push(year)行。

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

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

在这种情况下,代码的典型输出看起来像(基于您的示例):

{ 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

答案 1 :(得分:8)

您可以使用group_bymap的组合在一行中获取嵌套数组结构:

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

答案 2 :(得分:4)

我正在使用哈希表而不是数组,因为我认为这可能更有意义。但是,如果这是你喜欢的,那么改回使用数组是相当简单的。

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=>{10=>[5]}, 2009=>{8=>[1, 2], 9=>[3]}}

答案 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