Ruby, wielowymiarowe tablice i .each

Witam! Chcę zadać pytanie związane ze zwykłym Ruby. Mam taki kod:

[code]$walls = Array.new(2, Hash.new)
$walls[0][‘x’] = 100
$walls[0][‘y’] = 100
$walls[0][‘w’] = 100
$walls[0][‘h’] = 100

$walls[1][‘x’] = 200
$walls[1][‘y’] = 200
$walls[1][‘w’] = 100
$walls[1][‘h’] = 100

def drawWalls
$walls.each do |wall|
# $screen.fillRect(wall[‘x’], wall[‘y’], wall[‘w’], wall[‘h’], [0,0,0])
puts wall.to_s
end
end[/code]
I teraz to co zwraca ta funkcja (poprzez puts) to:

[quote]{“x” => 200, “y” => 200, “w” => 100, “h” => 100}
{“x” => 200, “y” => 200, “w” => 100, “h” => 100}[/quote]
Gdybym stworzył tablicę 10-elementową to linijka będzie powtórzona 10 razy. A nie muszę chyba tłumaczyć co chcę osiągnąć? Nie wiem czemu za zmienną wall podawany jest tylko ostatni element tablicy, zamiast najpierw pierwszy o indexie 0, a potem drugi o indexie 1. I jak zrobić, żeby to “działało” tak jak trzeba?

Zacznijmy od tego, że $walls to zmienna globalna - źródło wszelkiego zła. Przerób ten przykład tak, żeby nie było zmiennych globalnych.

A przechodząc do Twojego problemu - jest tutaj pewna subtelność - do wywołania Array.new(2, Hash.new) przekazujesz jedną i tę samą instancje tablicy asocjacyjnej.
Dlatego $walls[0] i $walls[1] to dokładnie ten sam obiekt.

W Rubim nie musisz z góry inicjować tablicy - możesz po prostu zrobić pustą tablicę i wypełniać ją w miarę potrzeb.
Co więcej - można prościej zainicjować t. asocjacyjna:

walls = [] walls[0] = {'x' => 100, 'y' => 100, 'w' => 100, 'h' => 100} walls[1] = {'x' => 200, 'y' => 200, 'w' => 100, 'h' => 100}

Dziękuję bardzo! Jestem początkujący w Ruby, poza tym umiem dobrze tylko PHP, więc gdy próbowałem zrobić tablicę multiwymiarową metodą:
tablica[][]
I mi zwróciło błąd zajrzałem do dokumentacji Ruby i tam znalazłem
Array.new(x, Hash.new)
I stąd to, że nie wiedziałem jak to Hash działa :slight_smile:

Ale czemu zmienna globalna jest zła? Ułatwia sprawę z dostaniem się do zmiennych wewnątrz funkcji.
I jak mówimy o zmiennych to co robi ze zmienną umieszczenie znaku @ przed nazwą zmiennej? Zauważyłem, że ludzie używają tego przy klasach. A nie wiem jak skonstruować zapytanie w Googlach bo pomija znak @, a dla zapytania “ruby at char” nic nie znajduje bo “at” to trochę zbyt uniwersalne słowo.

Jest zła, bo jest… globalna :wink: tzn. wszędzie jest do niej dostęp, wszędzie da się ją zmienić, i im więcej piszesz kodu, tym tak naprawdę masz mniejszą kontrolę nad tą zmienną (zmienisz ją w jednym miejscu, i posypie się kod w kompletnie innym). Jak pogooglasz to znajdziesz też pewnie kilka innych powodów, oraz sporo przykładów, gdzie używanie zmiennych globalnych może przynieść złe skutki.

zmienna z @ to zmienna instancji klasy
spotkasz się też ze zmiennymi z @@ przed nazwą - to zmienne klasy

Skoro nie wiesz dlaczego zmienne globalne są złe, to jeszcze musisz się dużo nauczyć :slight_smile:
Zasoby które mogą Ci się przydać:

ja tak jeszcze z zupełnie innej beczki: domyślam się, że piszesz jakąś grę. Jeśli tak, to polecam super (moim zdaniem) gem chingu :wink:

Na razie nie pisałem dużych projektów w Rubym, więc nie wiem, że zmienne globalne szkodzą i utrudniają debugowanie. W PHP nawet przy większych projektach nie wykorzystywałem w zasadzie globalnych, bo i nie odczuwałem takiej potrzeby - i tak miałem porządek w kodzie.

Odkopuję mój temat, gdyż znowu mam problem z wielowymiarowymi tablicami. Kod następujący mam:

p = Array.new(4, Array.new) n = 0 (0..3).each do |i| (0..3).each do |i2| p[i][i2] = n n += 1 end puts p.to_s + "\n\n" end
To co zwraca puts to:

[code][[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]

[[4, 5, 6, 7], [4, 5, 6, 7], [4, 5, 6, 7], [4, 5, 6, 7]]

[[8, 9, 10, 11], [8, 9, 10, 11], [8, 9, 10, 11], [8, 9, 10, 11]]

[[12, 13, 14, 15], [12, 13, 14, 15], [12, 13, 14, 15], [12, 13, 14, 15]][/code]
A według mnie powinno zwracać takie coś:

[code][[0, 1, 2, 3]]

[[0, 1, 2, 3], [4, 5, 6, 7]]

[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]

[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]][/code]
Bo w pętli jest taka sekwencja kluczy tablicy:
00, 01, 02, 03
10, 11, 12, 13
20, 21, 22, 23
30, 31, 32, 33
Czyli po pierwszym wykonaniu pętli powinien być jeden element (zawierający kolejne 0…3) w tablicy, a po drugim dwa (zawierający 0…3 i 4…7) itd. Natomiast czemu jest tak jak jest, nie mam pojęcia.

Zamień pierwszą linijkę na

p = Array.new(4) { Array.new }

To jest to, czego oczekujesz, a co zmyłkowo opisałeś jako “powinno”. Otóż nie, kod działa dokładnie jak powinien, natomiast Ty musisz poczytać o różnicy pomiędzy przekazywaniem kopii a referencji i jak to działa w Ruby.

Dobrze, trochę poeksperymentowałem i doszedłem do następujących wniosków:

  • Array to zwyczajna tablica.
  • Hash to tablica, gdzie klucze opisane są string’ami (^^).
  • array = Array.new(2, Array.new) dodawanie do tablicy za pomocą array[X][Y] = Z oznacza dodanie wartości Z na miejsce Y (w przypadku stringów jest to nie klucz tabeli, tylko pozycja w tekście) dla każdej wartości (w tym wypadku dla każdej tablicy) znajdującej się w tablicy głównej . Ale tutaj nie rozumiem jednej rzeczy. Czy X nie ma kompletnie żadnego zastosowania? Czy może ma [i]jakieś[/i[ zastosowanie.
  • array = Array.new(2) { Array.new } utworzenie tablicy, a następnie w każdej komórce utworzenie kolejnej tablicy.

Nie.

1.9.3-p194 :054 > hash = {1 => "int", "a" => "string", :b => "symbol", 2.5 => "float", Array.new => "array"} => {1=>"int", "a"=>"string", :b=>"symbol", 2.5=>"float", []=>"array"}

Spójrz na to tak:
Kod: array= Array.new(2, Array.new)
możesz zapisać tak:
a = Array.new
array = Array.new(2, a)

To oznacza to samo. Czyli tworząc tablicę array od razu wrzucasz do niej 2 razy ten sam obiekt, czyli array[0] i array[1] odnoszą się do tego samego miejsca w pamięci. Dlatego właśnie array[0][0] = “aaa” spowoduje, że array[1][0] też będzie miało taką wartość.
Czyli rzeczywiście w tym momencie nie ma różnicy do którego elementu głównej tablicy coś dodasz, bo wszystkie są tylko referencjami do tego samego obiektu.
Natomiast nie jest tak, że X nie ma tam zastosowania, bo możesz zrobić array[X] = [] i wówczas ten element będzie już się odnosił do innego miejsca.

Prawda pomieszania z fałszem i nieściłościami. Dlatego właśnie pisałem poczytaj. Czasem warto zamknąć irba i uzupełnić wiedzę w sposób bierny. To jest właśnie jeden z tych momentów.

Znaczy tak, miałem właśnie to na myśli, że możemy definiować klucze :smiley: Miałem napisać string’ami i innymi, ale jakoś mi wyleciało spod palców.

A polecacie może jakieś konkretne źródła w Internecie, gdzie można dotyczać o wielu szczegółach, krok po kroku? I dlatego nie chodzi mi właśnie o dokumentację, bo tam dla osoby początkującej jest naprawdę za duży bajzel w podawaniu informacji.

@soanvig: a czytałeś pierwszy temat w tym dziale? http://rubyonrails.pl/forum/t19-Jak-zaczac-przygode-z-Ruby-on-Rails

Tak. Pierwsze kroki mnie nie interesują. Większość to książki lub wprowadzenia. Natomiast ja szukam obszernego poradnika, coś na miarę dokumentacji, tylko że nie oficjalniej, bo jej “nie ogarniam”.

To polecam: http://helion.pl/ksiazki/ruby-programowanie-david-flanagan-yukihiro-matsumoto,rubypr.htm jest bardzo fajna bez lania wody.

Napisałem, że w Internecie, online, nie książki. PDF może być, ale nie książka do kupienia :smiley: Chcę spróbować swoich sił w Rubim, ale na razie bez inwestowania w to pieniędzy. Bo mam tendencję, że mi się różne rzeczy szybko nudzą i dlatego nie chcę kupować książki.

Polecam przerobić tryruby.org, kurs rubiego na apohllo.pl i może to? http://pl.wikibooks.org/wiki/Ruby
No coś poczytać trzeba : )

Danke schon