Skip to content

Enumeration ve Iteration

Sayılabilen nesneler Enumerator sınıfından türemişlerdir ve içinde döngü / tekrar yapılabilen nesneler haline geldikleri için de Iterable hale gelmişlerdir. Yani ne demek istiyorum?

["a", "b", "c"].class      # => Array
["a", "b", "c"].each.class # => Enumerator

["a", "b", "c"] aslında bir Array iken, #each method’unu çağırdığımız anda elimizdeki Array birden Enumerator haline geldi ve içinde iterasyon yapılabilecek yani teker teker dizi içindeki elemanlara erişip istediğimizi gibi kullanabileceğimiz bir hale geldi.

each_with_object, with_object

İki method’da aynı işi yapar. Elimizde Enumerator varsa, yani bu içinde dolaşılabilen bir nesne ise, bu iterasyona ara elementler takabiliriz.

Bu iki method, Enumerator’deki her elemana verilen şeyi takar. Aşağıdaki örnekte each_with_object("foo"), ["a", "b", "c"] dizisindeki her eleman içindir. Dolayısıyla, bu işlem sonrasında ne olduğunu anlamak için Enumeratorü to_a method’u ile Arraye çevirdik.

enumerator = ["a", "b", "c"].each
enumerator_with_foo = enumerator.each_with_object("foo")
enumerator_with_foo.to_a # => [["a", "foo"], ["b", "foo"], ["c", "foo"]]

Keza, bu durumda enumerator_with_foo da each method’unu kullanarak, each_with_object ile pas edilen nesneye de iterasyon esnasına ulaşabiliyoruz;

enumerator = ["a", "b", "c"].each
enumerator_with_foo = enumerator.each_with_object("foo")
enumerator_with_foo.each do |element, obj|
  puts "eleman: #{element}, obj: #{obj}"
end

# eleman: a, obj: foo
# eleman: b, obj: foo
# eleman: c, obj: foo

Elimizde Enumerator varsa, bir şekilde sıra / index bilgisi de var demektir;

sayilar = [1, 2, 3, 4].each
sayilar.next # => 1
sayilar.next # => 2
sayilar.next # => 3
sayilar.next # => 4
sayilar.next # => StopIteration hatası!

next method’unu kullanarak sonraki elemana ulaşabiliyoruz. Hatırlarsanız, Array’ler 0 index’lidir. Elimizdeki Array içinde dolaşırken index kullanmak istersek each_with_index method’unu kullanırız;

["Uğur", "Yeşim", "Ezel", "Ömer"].each_with_index do |name, index|
  puts "İsim: #{name}, index: #{index}"
end
# İsim: Uğur, index: 0
# İsim: Yeşim, index: 1
# İsim: Ezel, index: 2
# İsim: Ömer, index: 3

Keza for kullanarak da aşağıdaki gibi bir işlem yapabiliriz;

isimler = ["Uğur", "Yeşim", "Ezel", "Ömer"]
for isim in isimler
  puts "isim: #{isim}"
end
# isim: Uğur
# isim: Yeşim
# isim: Ezel
# isim: Ömer

next_values, peek, peek_values, rewind

Aynı next gibi çalışır fakat geriye Array döner ve ilgili index pozisyonunu ileri taşır. Sona geldiğinde de StopIteration hatası verir (Exception)

a = [1, 2, 3, 4].each
a.next        # => 1
a.next_values # => [2]
a.next_values # => [3]

peek ile next den sonraki değeri görürüz. Eğer sona gelinmişse yine StopIteration raise edilir.

a = [1, 2, 3, 4].each
a.next        # => 1
a.peek        # => 2

a.next        # => 2
a.peek        # => 3

a.next        # => 3
a.peek        # => 4

a.next        # => 4
a.peek        # => StopIteration: iteration reached an end

aynı next_values gibi peek_values de bize Array olarak bilgi verir next sonrasında kalan elemanları.

rewind ile pozisyonu başa alırız, yani kaydı geri sararız :)

a = [1, 2, 3, 4].each
a.next        # => 1
a.next        # => 2
a.next        # => 3
a.rewind      # => #<Enumerator: [1, 2, 3, 4]:each>
a.peek_values # => [1]
a.next        # => 1

Diğer Nesnelerdeki Enumeration Durumları

Fixnum

upto, downto, times

Bir sayıdan yukarı doğru sayarken upto, aşağı doğru sayarken downto ve kaç defa aynı işlemi yaparken de times kullanırız.

# 10’dan 5’e sayıyoruz, 10’da 5’de dahil..
10.downto(5){ |i| puts "Sayı: #{i}" }
# >> Sayı: 10
# >> Sayı: 9
# >> Sayı: 8
# >> Sayı: 7
# >> Sayı: 6
# >> Sayı: 5

# 5’den 10’a sayıyoruz, 10’da 5’de dahil..
5.upto(10){ |i| puts "Sayı: #{i}" }
# >> Sayı: 5
# >> Sayı: 6
# >> Sayı: 7
# >> Sayı: 8
# >> Sayı: 9
# >> Sayı: 10

# 3 defa block içindeki kod çalışsın
# 0’dan 3’e kadar 3 hariç :)
3.times{ |i| puts "#{i}" }
# >> 0
# >> 1
# >> 2

String

Aynı mantıkta upto ve downto ilginç bir şekilde String için de kullanılır. Örneğin A’dan itibaren M’ye kadar demek için:

"A".upto("M"){ |s| puts s }
# >> A
# >> B
# >> C
# >> D
# >> E
# >> F
# >> G
# >> H
# >> I
# >> J
# >> K
# >> L
# >> M

ya da, "AB", "AC", "AD" gibi sekans olarak gitmek gerektiğinde de;

"AB".upto("AE"){ |s| puts s }
# >> AB
# >> AC
# >> AD
# >> AE

tam tersi için downtokullanılır.