1.4.1.5. fejezet, Ciklusok és léptetők

Ciklusokból is sokféle van, ment több másik Ruby formulából. A megszokott for..do ciklust is sokféleképp írhatjuk le:

for i in [1,2,3] do
  puts( i )
end
 
for s in ['one','two','three']
  puts( s )
end
 
for s in 1..3 
  puts( s ) 
end
 
for s in ['one','two','three'] do puts( s ) end
 
[1,2,3].each do |i|
  puts( i )
end
 
(1..3).each do |s| puts(s) end
 
for i in (1..10) do
  puts( i )
end

Többdimenziós tömbökre is van for iterátor, erre már láttunk is korábban példát

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

While ciklusok

Az előbb elől-tesztelő ciklusokat láthattunk. Itt következnek az elől- és hátul-tesztelő ciklusok, a while és az until. Mindkettő használható elől- és hátul-teszteléshez.

begin 
  sleep 
  snore 
end while tired
 
while tired do sleep end
 
while tired
  sleep
end
 
sleep while tired

Ugyanez until használatával:

i = 0
 
until i == 10 do
  puts(i)
  i+=1
end
 
begin 
  puts(i) 
end until i == 10
 
until i == arr.length
  puts(arr[i]) 
  i +=1
end

Talán így egyszerűbb különbséget tenni:

while i < arr.length
  puts(arr[i]) i += 1
end
 
until i == arr.length
  puts(arr[i]) i +=1
end

Egy különösen összetett és bonyolult módja az iterációnak:

i=0
loop { 
  puts(arr[i])
  i+=1
  if (i == arr.length) then
    break
  end
}

Megszámlálhatóság

Az Enumerable modul korábban bekerült már az Array osztályba, így a tömbelemeknek van egy speciális lekérdezése: include?, és néhány hasznos metódusa:

arr = [1,2,3,4,5]
y = arr.collect{ |i| i }     #=> y = [1, 2, 3, 4]
z = arr.collect{ |i| i * i } #=> z = [1, 4, 9, 16, 25]
 
arr.include?( 3 ) #=> true 
arr.include?( 6 ) #=> false 

A tömb értékek minimuma és maximuma is könnyen megállapítható:

arr.min #=> 1 
arr.max #=> 5

A Hash táblánál minden szöveges kulcs mező értékeit ASCII betűkké alakít a fenti két függvény, és ezek adják a szám szerinti minimum és maximum értéket. Az alábbi két metódussal felülírható ez az összehasonlítás:

h.min{ |a,b| a[0].length <=> b[0].length }
h.max{|a,b| a[0].length <=> b[0].length }

Tehát a következő Hash táblát:

{„one‟=>for sorrow‟, „two‟=>for joy‟}

Így kapja meg a két függvény:

a = [„one‟,‟for sorrow‟]
b = [„two‟,‟for joy‟]

Mindkettőnek a 0. indexe a kulcs index. Ennek a hosszát hasonlítja össze. Ha az értéket szeretnénk összehasonlítani, csináljuk így:

p( h.min{|a,b| a[1].length <=> b[1].length } )
p( h.max{|a,b| a[1].length <=> b[1].length } )

Ha a szerint szeretnénk összehasonlítani, ami szerint kimondják angolul, akkor csinálunk egy tömböt a kimondásnak megfelelő sorrendű tartalommal:

str_arr=['one','two','three','four','five','six','seven']

és ezt használjuk fel az összehasonlításhoz:

h.min{|a,b| str_arr.index(a[0]) <=> str_arr.index(b[0])}
  #=> ["one", "for sorrow"]
h.max{|a,b| str_arr.index(a[0]) <=> str_arr.index(b[0])}
  #=> ["seven", "for a secret never to be told"]

Mint korábban írtam, az Enumerable modul tartalmazza a min,max,collect metódusokat. Ha saját osztályban szeretnénk csinálni ilyen iterációt, be kell emelni az Enumerable osztályt.

class MyCollection
  include Enumerable
  def initialize( someItems )
    @items = someItems
  end
  def each
    @items.each{ |i| 
      yield( i )
    } 
  end
end
 
things = MyCollection.new(['x','yz','defgh','ij','klmno'])
 
p( things.min ) #=> "defgh"
p( things.max ) #=> "yz"
p( things.collect{ |i| i.upcase } ) #=> ["X", "YZ", "DEFGH", "IJ", "KLMNO"]

Ha másképp szeretnénk összehasonlítani, egyszerűen írjuk felül a metódusokat:

def min 
  @items.to_a.min{|a,b| a.length <=> b.length } 
end
 
def max 
  @items.to_a.max{|a,b| a.length <=> b.length }
end

A yield metódus a kapott blokkot a paramétereket felhasználva végrehajtja, így pl. a min, max, vagy collate blokkokat. Ezért az each metódust így definiáljuk:

def each 
  @items.each{ |i|
    yield( i )
  } 
end

A yield metódus így is szemléltethető:

def test
   puts "You are in the method"
   yield
   puts "You are again back to the method"
   yield
end
test {puts "You are in the block"}

Kimenet:

You are in the method
You are in the block
You are again back to the method
You are in the block

Paramétereket is átadhatunk a yield-nek.

def test
   yield 5
   puts "You are in the method test"
   yield 100
end
test {|i| puts "You are in the block #{i}"}

Eredménye:

You are in the block 5
You are in the method test
You are in the block 100

Ha több paramétert is átadunk a yield-nek, vesszővel elválasztva hívjuk meg.

yield a, b

Majd a test blokk meghívását is módosítjuk:

test {|a, b| statement}