2009-08-05 31 views
5

Mam pytanie rubinowe dla początkujących o wielowymiarowych tablicach.Jak zrobić dynamiczną tablicę wielowymiarową w ruby?

Chcę sortować wpisy według roku i miesiąca. Więc chcę stworzyć wielowymiarową tablicę, która zawiera rok -> miesiąc -> Wpisy miesiąca

więc tablica będzie jak:

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

Teraz mam:

@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 

ale gdy próbuję wykonać iterację tablicy lat, otrzymuję: „niezdefiniowanej metody` każdy”za rok 2009: Fixnum”

Próbowano również:

@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 

Odpowiedz

11

otrzymujesz błąd, ponieważ FixNum (czyli liczba) jest popychany na tablicy, w wierszu, który czyta @years.push(year).

Twoje podejście do używania tablic na początek jest nieco wadliwe; Tablica jest idealna do przechowywania uporządkowanej listy przedmiotów. W twoim przypadku masz odwzorowanie od kluczy do wartości, co jest idealne dla skrótu.

Na pierwszym poziomie klucze są latami, wartościami są hasze. Skróty drugiego poziomu zawierają klucze miesięcy i wartości tablic wpisów.

W tym przypadku, typowy wyjście kodu wyglądałby mniej więcej tak (w oparciu na przykład):

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

Uwaga, jednak kolejność latach i miesiącach nie jest gwarancją w dowolnej konkretna kolejność. Rozwiązaniem jest zazwyczaj zamawianie kluczy, kiedy tylko chcesz do nich dostęp. Teraz kod, który będzie generować takie wyjście (opartą na układzie kodu, choć może być znacznie 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

Dzięki . – jussi

+0

Nie ma za co. Spójrz na odpowiedź Michaela_Sepcota, aby dowiedzieć się, jak to zrobić w bardziej "zaradny sposób". –

+0

Dzięki! Nareszcie rozumiem to –

4

używam tabel mieszania zamiast tablic, ponieważ myślę, że to prawdopodobnie ma sens tutaj. Jednak całkiem banalnie jest wrócić do korzystania z tablic, jeśli wolisz.

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 

Wyjście jest: {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

można uzyskać zagnieżdżonych rozmieszczonymi w jednej linii za pomocą kombinacji group_by s oraz map: dla mnie oświecić

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

Czy nie jest to grupa po dodaniu szyn, a nie zwykły stary rubin? –

+1

Nie, chodzi o Ruby 1.8.7. –

+0

Ah - Próbowałem go na Ruby 1.8.6. –

Powiązane problemy