1.4.1.4. fejezet, Tömbök, Hash táblák és halmazok

Tömbökről már volt szó érintőlegesen, most nézzük meg közelebbről ezeket. Azt tudjuk már, hogy 0 index jelenti a tömb első elemét. Most nézzünk egy több típusból álló tömböt:

def hello 
  return "Szevasz tavasz" 
end
 
x = [1+2, hello, `dir`]

Az első elem a 3-as érték, a második egy String ("Szevasz tavasz"), a harmadik szintén egy String ha Windowson futtatjuk, és visszaadja az aktuális könyvtárban található fájlok nevét dupla sortörés jellel elválasztva. Ha a fájlok tömbjét szeretnénk visszakapni, használjuk inkább az alábbi kódot:

puts(Dir.entries( 'C:\\' ))

Stringből a

y = %w( this is an array of strings )

kifejezéssel is gyárthatunk tömböt. Tömb objektum a new metódussal is készíthető:

a = Array.new # an empty array
a = Array.new(2) # [nil,nil]
a = Array.new(2,"hello world") # ["hello world","hello world"]

Több dimenziós tömbök

Egyrészről a new metódusnak átadott paraméterekkel hozhatunk létre több dimenziós tömböt:

a = Array.new(2)
a[0]= Array.new(2,'hello')
a[1]= Array.new(2,'world')

A kódba beégetett több dimenziós tömböt így jelöljük:

a = [ 
     [1,2,3,4],
     [5,6,7,8],
     [9,10,11,12],
     [13,14,15,16] ]

vagy például:

multiarr = [['one','two','three','four'],[1,2,3,4]]

for ciklus tömbökre

Tömbelemek kiírására használhatjuk a for ciklust a következő módon:

for i in multiarr
  puts(i.inspect)
end

Eredménye

["one", "two", "three", "four"]
[1, 2, 3, 4]

Hogyan sorolhatnánk fel a tömb összes elemét egyszerűen?

for (a,b,c,d) in multiarr
  print("a=#{a}, b=#{b}, c=#{c}, d=#{d}\n" )
end

vagy pl.:

for row in multiarr
  for item in row
    puts(item)
  end
end

A tömb indexelése ugyan úgy történik, mint a stringeknél láttuk:

arr = ['h','e','l','l','o',' ','w','o','r','l','d']
print( arr[0,5] )    #=> "hello"
print( arr[-5,5 ] )  #=> "world"
print( arr[0..4] )   #=> "hello"
print( arr[-5..-1] ) #=> "world"

Tömböt létrehozhatunk egyszerűbb jelöléssel is:

arr = []
arr[0] = [0]
arr[1] = ["one"]
arr[3] = ["a", "b", "c"]

Az arr tömb tartalma:

[[0], ["one"], nil, ["a", "b", "c"]]

Paraméter átadás tömbből

def counter(a,b,c)
  (1..3).each{|j|
    a*=j
    puts("#{j}. a=#{a}")
  }
  (1..3).each{|j|
    b*=j
    puts("#{j}. b=#{b}")
  }
  (1..3).each{|j|
    c*=j
    puts("#{j}. c=#{c}")
  }
end
 
a=[2,3,4]
counter(*a) 
p( a )

Eredménye:

1. a=2
2. a=4
3. a=12
1. b=3
2. b=6
3. b=18
1. c=4
2. c=8
3. c=24
[2, 3, 4]

Tömb másolásánál használjuk a clone metódust, mert az egyenlőségjel cím szerint adja át a másolandó tömböt, így ha bármelyikben értéket változtatunk, az megjelenik mindkettőben.

Tömbök összehasonlítása

Tömbök összehasonlítására használjuk a <=> jelölést.

[0,10,20] <=> [0,20,20]

Ha a bal oldali érték kisebb (mint fent), a visszatérési érték -1. Ha a jobb oldali, akkor 1, ha egyenlő, akkor 0 értéket kapunk vissza.

Tömbök sorba rendezése

Tömb sorba rendezése egy saját összehasonlító függvénnyel:

arr.sort{
 |a,b|
  a.to_s <=> b.to_s
}

Osztály metódusában definiálva:

class MyArray < Array
  include Comparable
  def <=> ( anotherArray )
    self.length <=> anotherArray.length
  end
end

Miután a standard ruby tömb nem tartalmazza a Comparable modult, ezért az egyszerű <,==,> összehasonlítások NoMethodError kivételt generálnak. Ha szükség van ezek használatára, egyszerűen emeljük be ezt a modult a következő kép:

class Array2 < Array
  include Comparable
end

Hash táblák

Hash táblát így hozhatunk létre:

h1 = Hash.new
h2 = Hash.new("Some kind of ring")
puts(h2[0])
Some kind of ring

Hash táblánál az index bármely típusú lehet. Jelen esetben ez string típusú:

h2['treasure1'] = 'Silver ring'
h2['treasure2'] = 'Gold ring'
h2['treasure3'] = 'Ruby ring'
h2['treasure1'] = 'Sapphire ring'

Természetesen az utolsó értékadás megváltoztatja a treasure1 kulcsú értéket. A hash tábla kulcstömbjére a keys metódussal, az értéktömbjére a values metódussal hivatkozhatunk. Hash táblák metszetét a & kifejezéssel kapjuk vissza. Pl.:

h1 = {'key1'=>'val1', 'key2'=>'val2', 'key3'=>'val3', 'key4'=>'val4'} 
h2 = {'key1'=>'val1', 'KEY_TWO'=>'val2', 'key3'=>'VALUE_3', 'key4'=>'val4'}
 
p( h1.keys & h2.keys ) # keys tömb metszete       #=> ["key1", "key3", "key4"]
p( h1.values & h2.values ) # values tömb metszete #=> ["val1", "val2", "val4"]
 
p( h1.keys+h2.keys ) # összefűzés
#=> [ "key1", "key2", "key3", "key4", "key1", "key3", "key4", "KEY_TWO"]
 
p( h1.values-h2.values ) # különbség
#=> ["val3"]
 
p( (h1.keys << h2.keys).flatten.reverse ) # összefűzi a két hash kulcstömböket, egy dimenziósítja keletkezett tömböt (<b>flatten</b> metódus) majd megfordítja az újonnan keletkezett tömböt (<b>reverse</b> metódus)
#=> ["KEY_TWO", "key4", "key3", "key1", "key4", "key3", "key2", "key1"]

Ez utóbbinál figyeljünk kicsit oda. Nézzük meg az összefűzést számokkal.

a =[1,2,3]
b =[4,5,6]
c = a + b  #=> c=[1, 2, 3, 4, 5, 6]
a << b     #=> a=[1, 2, 3, [4, 5, 6]]

A második összefűzésnél látszik, hogy a "b" tömböt mint egy elemet fűzi hozzá az "a" tömbhöz. Az a.flatten ezt "simítja ki".

a.flatten  #=> [1, 2, 3, 4, 5, 6]

Halmazok

Nagyon hasonlít a tömbök kezelésére.

s1 = Set.new( [1,2,3, 4,5,2] )
s2 = Set.new( [1,1,2,3,4,4,5,1] )
s3 = Set.new( [1,2,100] )

Egy elem hozzáadása:

s1.add( 1000 )

Egy halmaz hozzáfűzése:

s1.merge(s2)

Két halmaz összehasonlítása:

p( s1 == s2 ) #=> true, minden duplikációt kivesz az összehasonlításkor

(Lásd még a Matrix és a Vector osztályokat)