2009-08-05 30 views
5

Tôi có câu hỏi ruby ​​mới bắt đầu về mảng đa chiều.Làm thế nào để tạo mảng đa chiều động trong ruby?

Tôi muốn sắp xếp các mục theo năm và tháng. Vì vậy, tôi muốn tạo một mảng đa chiều mà sẽ chứa năm -> tháng -> mục của tháng

Vì vậy, các mảng sẽ như thế nào:

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

Bây giờ tôi có:

@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 

nhưng khi tôi cố gắng lặp qua mảng năm, tôi nhận được: "phương pháp chưa xác định` mỗi 'cho năm 2009: Fixnum "

Đã thử:

@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 

Trả lời

11

Bạn nhận được lỗi vì một số FixNum (có nghĩa là một số) được đẩy lên mảng, trong dòng ghi @years.push(year).

Cách tiếp cận của bạn khi sử dụng Mảng để bắt đầu là một chút thiếu sót; một mảng là hoàn hảo để giữ một danh sách thứ tự các mục. Trong trường hợp của bạn, bạn có một ánh xạ từ các khóa đến các giá trị, nó hoàn hảo cho một Hash.

Ở cấp độ đầu tiên, các khóa là năm, các giá trị là băm. Các băm cấp thứ hai chứa các khóa của các tháng và các giá trị của mảng các mục.

Trong trường hợp này, một đầu ra tiêu biểu của mã của bạn sẽ giống như thế (dựa trên ví dụ của bạn):

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

Chú ý rằng, tuy nhiên, thứ tự của năm và tháng không đảm bảo thể ở bất kỳ thứ tự cụ thể. Giải pháp là bình thường để đặt hàng các phím bất cứ khi nào bạn muốn truy cập chúng. Bây giờ, một mã mà sẽ tạo ra như một đầu ra (dựa trên cách bố trí của bạn mã, mặc dù có thể được thực hiện nhiều 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 
+0

Cảm ơn soi sáng cho tôi . – jussi

+0

Bạn được chào đón. Nhìn vào câu trả lời của Michael_Sepcot về cách làm theo cách _rubyish_ hơn. –

+0

Cảm ơn! Cuối cùng tôi hiểu điều này –

4

Tôi đang sử dụng bảng băm thay vì mảng, vì tôi nghĩ rằng nó có thể có ý nghĩa hơn ở đây. Tuy nhiên, nó khá tầm thường để thay đổi trở lại sử dụng mảng nếu đó là những gì bạn thích.

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 

Đầu ra là: {2007=>{10=>[5]}, 2009=>{8=>[1, 2], 9=>[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 
8

Bạn có thể lấy cấu trúc mảng lồng nhau trong một dòng bằng cách sử dụng một sự kết hợp của group_by s và map:

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

Không phải là group_by một bổ sung đường ray, không đồng bằng cũ ruby? –

+1

Không, nó có trong Ruby 1.8.7. –

+0

Ah - Tôi đã thử nó trên Ruby 1.8.6. –

Các vấn đề liên quan