10 Şubat 2025 Pazartesi

Ruby Temelleri 1

https://ujk-ujk.blogspot.com/2025/02/ruby-temelleri-1.html
İçindekiler +

    Ruby birçok platformda çalışan, açık kaynak, dinamik, nesne temelli, yorumlamalı bir dildir. Basit ve üretken olmak amaçlı geliştirilmiştir. 1995 yılında Yukihiro Matsumoto (Matz) tarafından geliştirilmiştir.

    Bu yazıda Ruby'nin temel tekniklerini inceleyeceğiz. Ruby programlama dili hakkında bilgilendirme amaçlayan Wikibooks Ruby Tercümesi de tarafımdan büyük kısmı yapılmış bir tercüme olarak birçok bilgi içeriyor. Okumanızı tavsiye ederim.


    Merhaba Dünya

    Ruby programlama dilinin bilgisayarınızda kurulu olduğunu kabul ederek ilk programı yazmaya başlayalım. Ben genelde Ubuntu işletim sisteminde ve editör olarak da VSCode editör kullanıyorum.

    Şimdi denemelerimizi yapacağımız bir klasör oluşturup içinde ilk programımız olan merhaba.rb dosyasını ekleyelim ve içine şu kodu yazalım:

    puts 'Merhaba Dünya!'

    Komut satırında (terminalde) bu programı çalıştırmak için,

    $ ruby merhaba.rb

    Burada $ işareti terminal emülatör programınızdaki prompt'u ifade eder, herkesin sisteminde farklı birşey yazar, gösterim için genelde $ işareti kullanılır.

    Terminalde bunu yazıp enter bastığımızda programımız çalışır ve şu çıktıyı verir:

    Merhaba Dünya!

    Programı çalıştırdığımız anda bu çıktı ekrana hemen yazılır. Ruby program dosyaları çalışmadan önce derlenmeye gerek duymaz. Ruby yorumlayıcısı (interpreter) çalışma zamanında bu kodu derler ve çalıştırır.



    Unix Benzeri Sistemlerde Kendiliğinden Çalışan Kod Dosyası Oluşturmak

    Kod dosyamıza yorumlayıcı direktif satırı (shebang) ekleyebiliriz. 

    #!/usr/bin/env ruby

    puts 'Merhaba Dünya!'

    Betik dosyamıza (merhaba.rb) çalıştırılabilir özelliği vermek için terminalde :

    $ chmod u+x merhaba.rb

    Artık dosyamızı ismini vererek çalıştırabiliriz.

    $ ./merhaba.rb

    Bir ayrıntı verelim,  ruby merhaba.rb derken dosya ismini direk yazmıştık, niye dosyayı sisteme direk çalışır olarak tanıtınca merhaba.rb deyince çalışmıyor da illa ./merhaba.rb şeklinde aynı klasörde olduğumuz dosyaya yol gösteriyoruz? Sebebi sistemin güvenlik kaygıları, Unix sistemler çalıştırılabilir dosyaları sadece kendilerine tanımlı uygulama çalıştırma klasörlerinde ararlar, içinde bulunduğunuz klasörde dahi olsa çalıştırılabilir dosya aranmaz. Ancak ve ancak dosyanın PATH bilgisini vererek çalıştırabilirsiniz.

    Shebang satırı, dosyada ilk satır olur,  "#!" ile başlar ve Ruby yorumlayıcı uygulamasının yerini belirtir. Aslında yorumlayıcının yeri kullanıcı ya da sistem bazında kurulum yapmış olmanıza göre (mesela usr/bin/ruby veya usr/local/bin/ruby) değişir, ama burada gösterilen /usr/bin/env ruby ruby programının olduğu yeri otomatik bulur.

    Kod dosyanızı artık sisteme çalıştırılabilir olarak bildirdiğiniz için , içindeki kodu değiştirseniz bile en istteki shebang satırı değiştirmedikten sonra direk çalışır olmaya devam edecektir.



    IRB Programında "Merhaba Dünya" Kodu

    irb uygulaması Ruby kod satırlarınızı direk olarak yazıp denemek amaçlı kullanılır. Bir şeyler test etmek için faydalıdır. Terminalde bir irb oturumu açmak için :

    $ irb

    Komutunu girdiğimizde karşımıza standart irb prompt'u çıkar.

    irb(main):001:0>

    Kısa prompt ile çalışmak için terminalde

    $ irb --simple-prompt

    Komutu girerseniz prompt şöyle olur:

    >>

    Önce çıkmasını öğrenelim. Irb oturumunu sonlandırmak için prompt yanına exit yazarsınız.

    Şimdi irb satırına Ruby kodumuzu girelim :

    >> puts "Merhaba Dünya!"

    Enter bastığımızda kodumuz hemen çalıştırılır ve ekrana şunu yazar:

    >> puts "Merhaba Dünya!"
    Merhaba Dünya!
    => nil
    >>

    İlk satır, kodumuz çalışınca gerçekleşen çıktı yazma işleminin sonucudur — ekrana Merhaba Dünya! yazar. İkinci satır ise satırda kullandığımız puts metodundan dönen değer olan nil'dir (ki dönen değer neymiş ileride göreceğiz). 

    puts deyimi ekrana yazı yazdıktan sonra alt satıra geçer, eğer alt satıra geçilmesini istemiyorsak (yani daha o satıra ileride eklemek istediklerimiz varsa) print deyimini kullanırız.

    >> print "Merhaba Dünya!"
    Merhaba Dünya!=> nil
    >>



    Kod Dosyası Olmadan Merhaba Dünya Kodunu Çalıştırmak

    Terminalde bir Ruby kodunu direk olarak çalıştırmanın da bir yolu var. Şimdi şu minicik tek satırlık kodumuzu , dosya oluşturmadan çalıştırmak için terminalde şunu girelim:

    $ ruby -e 'puts "Merhaba Dünya!"'

    Daha uzun programları Ruby yorumlayıcısına here döküman kullanarak girebiliriz.

    $ ruby <<END
    > puts "Merhaba Dünya!"
    > puts "İkinci Satır"
    > END

    Çıktısı :

    Merhaba Dünya!
    İkinci Satır



    İlk Metodumuz

    Metodlar belirli işlerimizi tekrar tekrar yapabilmek için aynı kodları tekrar takrar yazmamak amacıyla, bir grup kodu bir blok içinde toplayıp ona bir isim vererek oluşturulur. Daha sonra bu isim kullanılarak aynı kodları defalarca çalıştırabiliriz.

    Şimdi ilk_metodum.rb adında yeni bir kod dosyası üretip içine şunu yazalım:

    def merhaba
        puts "Merhaba Dünya!"
    end

    def kelimesi Ruby'ye bir metod tanımlamakta olduğumuzu anlatıyor (def-ining). Metodumuzun adı ise merhaba.

    puts "Merhaba Dünya!" , bildiğimiz gibi konsola Merhaba Dünya! yazar. 

    end deyimi tanımladığımız merhaba metodunun bittiğini ifade eder.

    Bu programı bu haliyle çalıştırırsanız hiçbir şey yapmaz. Çünkü metodu sadece tanımladık, ama kullanmadık. Metodu kullanmak için onu çağırmalıyız. Çağırmak için metodun adını yazmamız gerekir.

    def merhaba
        puts "Merhaba Dünya!"
    end

    merhaba()  # diğer programlama dilleri gibi
    merhaba    # Ruby gibi

    merhaba() şeklinde parantezli kullanım hemen tüm diğer programlama dillerinde metod çağırma şeklidir. Ruby'de parantezleri kullanmadan da metod çağırabiliriz. Gerçi ileride parametreleri olan metodlarda mecburen parantezleri kullanmak gerekebilecektir. Ama Ruby şeklini kullanmaya özen göstersek daha iyi olacaktır.

    Programımızı çalıştırırsak çıktısı şöyle olur :

    $ ruby ilk_metodum.rb
    Merhaba Dünya!
    Merhaba Dünya!

    Her iki kullanım şekli de sağlıklı çalışıyor.




    Veri Tipi Dönüşümleri

    Ruby'de bir veri tipinden diğerine dönüştürme yapmak için öntanımlı metodlar vardır.


    -- Float değere dönüştürmek

    Bir irb oturumu açın ve şunları deneyin :

    >> "123.45".to_f
    => 123.45
    >> Float("123.45")
    => 123.45

    Ruby kullanıyoruz Float metodunu parantez olmadan da kullanabiliriz.

    >> Float "123.45"
    => 123.45

    to_f string nesnelere ait bir öntanımlı metod ve verilen string değeri kayan noktalı sayıya çeviriyor. Burada gördüğümüz "123.45" değeri bir string (karakter dizisi) nesnesidir, merak etmeyin onları da göreceğiz. Bir nesneye ait metodlar nesne arkasına nokta ve metod adı eklenerrek çağrılır, burada da "123.45".to_f şeklini görüyorsunuz.

    Float ise kayan noktalı sayıların ifade edildiği nesnelerin üretildiği sınıf adı. Ruby dilinde her şey bir nesnedir ve 123.45 de aslında öyle düz bir değer değil bir nesnedir. Hangi sınıftan bir nesne olduğunu görmek için irb satırına 

    >> 123.45.class
    => Float

    Gördüğümüz gibi bir basit sayı değil, bir Float nesnesi, ki bunu zaten .class metodunu çağırırken kabul ediyoruz, metodlar nesnelere uygulanır.

    Ama ya sayıya dönüştürülemeyecek bir değer verirsek? Mesela 

    >> "birşey".to_f
    => 0.0
    >> Float "birşey"
    <internal:kernel>:173:in `Float':
    invalid value for Float(): "bir\xC5\x9Fey" (ArgumentError)

    to_f metodu sayı olmayan değere karşılık 0.0 değerini üretirken Float() argüman değerinde hata mesajı vererek başarısız oldu.


    -- String değere dönüştürmek

    Hadi şimdi tersini yapalım.

    >> 123.45.to_s
    => "123.45"
    >> String 123.45
    => "123.45"

    Genelde String() çağrısı doğrudan verilen argümanın #to_s metodunu çağırır.

    Kernel#sprintf ve String#% metodları davranışları C diline benzer:

    >> sprintf "%s", 123.4
    => "123.4"
    >> "%s" % 123.4
    => "123.4"
    >> "%d" % 123.4
    => "123"
    >> "%.2f" % 123.5
    => "123.50"



    -- Integer değere dönüştürmek

    Tamsayı değere dönüşütürmek için kullanılan yöntemler :

    >> "123.45".to_i
    => 123
    >> 123.45.to_i
    => 123
    >> Integer "123"
    => 123

    Son örnekteki Integer deyimi bir float sayı string şeklinde verilirse dönüştürme yapmaz, tamsayı değeri string olarak yazılmalıdır. 

    İstersenin  123.45.to_i ifadesini daha anlaşılabilir olması için (123.45).to_i şeklinde yazabilirsiniz. 

    Bir tamsayı değerle başlayan her string değer tamsayıya dönüştürülebilir, ama sayı ile başlamıyorsa dönüştürülemez.

    >> "123-foo".to_i
    => 123
    >> "foo-123".to_i
    => 0

    İki yöntem arasında float'da olduğu gibi fark vardır.

    >> "birşey".to_i
    => 0
    >> Integer "birşey"
    : "birşey" (ArgumentError)



    -- Float ve Integer

    >> 1 / 2
    => 0

    İki tamsayının bölümü yine tamsayı olmalıdır, örnekte sonuç 0.5 olamaz, tamsayı kısmı olan 0 alınır.

    Eğer kayan noktalı sayı olarak sonuç istiyorsak en az bir sayıyı Float şeklinde ifade etmeliyiz.

    >> 1.0 / 2
    => 0.5
    >> 1 / 2.0
    => 0.5
    >> 1.0 / 2.0
    => 0.5

    Ya da değerleri Float'a dönüştürerek kullanabiliriz.

    >> 1.to_f / 2
    => 0.5
    >> 1 / Float(2)
    => 0.5

    İkinci örnekte Float() metodunu parantezlerle ifade ettik, çünkü önce 2 sayısının Float yapılmasını , sonra bölme işlemi yapılmasını istiyoruz. 

    Alternatif olarak fdiv metodu değerleri dönüştürmeden float işlem yapmak için kullanılabilir.

    >> 1.fdiv 2
    => 0.5

    Demek ki fdiv metodu Integer sınıfının bir oluşum metodu.




    Array Değerler

    Array , içinde birçok değer barındıran bir nesnedir. Ruby'de her şay bir nesne olduğu için array içinde birçok nesne barındıran bir nesne de denebilir. 

    Bir array şu şekillerde ifade edilebilir :

    a = []          # array değer ifadesi kullanarak tanımlama

    a = Array.new   # yukarıdaki satırla aynı anlamda
                    # sınıf adından oluşum nesnesi üretilmiş

    a = Array.new(5)    # 5 elemanlı bir array üretir, tüm elemanlar 'nil' değerinde
    a = Array.new 5     # yukarıdaki satırın parantezsiz hali

    a = Array.new 5, 0  # 5 elemanlı bir array üretir, tüm elemanlar 0 değerinde


    -- String elemanları olan array

    Elemanları string değerler olan bir array,

    array1 = ["bir", "iki", "üç", "dört"]

    Bu satırı Ruby %w operatörü kullanarak şöyle yazabiliriz. 

    array1 = %w(bir iki üç dört)%w()

    %w()  yapısında sınırlayıcı karakterler olarak eşleşmesi olan herhangi bir karakter çifti kullanılabilir, mesela %w{...}%w[...]%w<...>

    Ayrıca birbiri ile aynı alfanumerik olmayan karakterler de kullanılabilir. Mesela :  %w!...! , %w#...# veya %w@...@.

    String içinde enterpolasyon yapılacaksa (yani bir Ruby işlemin sonucu yazılacaksa), %w değil, büyük harf %W kullanmak gerekir.

    var = 'merhaba'

    %w(#{var}) # => ["\#{var}"]
    %W(#{var}) # => ["merhaba"]

    Çok kelimeden oluşan değerler boşluk öncesine \ koyarak birleşik oldukları belirtilebilir.

    >> %w(Colorado California New\ York)
    => ["Colorado", "California", "New York"]


    -- Array.new ile yeni bir array üretmek

    Boş bir array ([ ]), Array sınıfının sınıf metodu olan Array::new kullanarak üretilebilir. 

    >> Array.new #=> []

    Array eleman sayısını vereceğiniz ilk argümanla girebilirsiniz.

    >> Array.new 3
    => [nil, nil, nil]

    Bir array'i default değerlerle doldurmanın iki yolu vardır :

    • İkinci argümanda sabit bir değer vermek
    • Bir kod bloğu yardımıyla, index numarasını da alarak değiştirilebilir değerler vermek

    >> Array.new 3, :x
    => [:x, :x, :x]
    >> Array.new(3) { |i| i.to_s }
    => ["0", "1", "2"]

    Birinci yöntem tavsiye edilmez , çünkü tüm elemanları aynı değere sabitler.

    >> a = Array.new 3, "X"
    => ["X", "X", "X"]
    >> a[1].replace "C"
    => "C"
    >> a
    => ["C", "C", "C"]

    Elemanın birini değiştirdik , hepsi değişti.

    Mantıklı olan ilkinci yöntemi kullanmak.

    >> b = Array.new(3) { "X" }
    => ["X", "X", "X"]
    >> b[1].replace "C"
    => "C"
    >> b
    => ["X", "C", "X"]

    Kod bloğu olayına da gireceğiz, merak etmeyin.


    -- Sembol elemanları olan array

    Elemanları sembol değerler olan bir array tanımlarken %i operatörü kullanılır.

    >> array1 = %i(bir iki üç dört)
    => [:bir, :iki, :üç, :dört]

     %i(...) yerine, %i{...} veya %i[...] veya %i!...! da kullanılabilir. 

    Eğer enterpolasyon yapacaksanız %I kullanmalısınız.

    >> a = 'merhaba'
    >> b = 'naber'
    >> array_bir = %I(#{a} #{b} hoşçakal)
    => [:merhaba, :naber, :hoşçakal]
    >> array_iki = %i(#{a} #{b} hoşçakal)
    => [:"\#{a}", :"\#{b}", :hoşçakal]


    -- Array elemanlarını işlemek

    Eleman eklemek :

    >> [1, 2, 3] << 4
    => [1, 2, 3, 4]

    >> [1, 2, 3].push 4
    => [1, 2, 3, 4]

    >> [1, 2, 3].unshift 4
    => [4, 1, 2, 3]

    >> [1, 2, 3] << [4, 5]
    => [1, 2, 3, [4, 5]]


    Eleman silmek :

    >> arr = [1, 2, 3, 4]
    >> arr.pop
    => 4
    >> arr
    => [1, 2, 3]

    >> arr = [1, 2, 3, 4]
    >> arr.shift
    => 1
    >> arr
    => [2, 3, 4]

    >> arr = [1, 2, 3, 4]
    >> arr.delete 1  # değeri 1 olan elemanı siler
    => 1
    >> arr
    => [2, 3, 4]

    >> arr = [1, 2, 3, 4, 5, 6]
    >> arr.delete_at 2  # 2 index nolu elemanı siler
    => 3
    >> arr
    => [1, 2, 4, 5, 6]

    >> arr = [1, 2, 2, 2, 3]
    >> arr - [2]    # tüm 2 değerli elemanlar çıkarıldı
    => [1, 3]
    >> arr - [2, 3, 4]  # 4 bir şey yapmaz
    => [1]
    >> arr
    => [1, 2, 2, 2, 3]


    Array'leri birleştirmek :

    >> [1, 2, 3] + [4, 5, 6]
    => [1, 2, 3, 4, 5, 6]

    >> [1, 2, 3].concat [4, 5, 6]
    => [1, 2, 3, 4, 5, 6]

    >> [1, 2, 3, 4, 5, 6] - [2, 3]
    => [1, 4, 5, 6]

    >> [1, 2, 3] | [2, 3, 4]
    => [1, 2, 3, 4]

    >> [1, 2, 3] & [3, 4]
    => [3]


    Ayrıca array ile çarpma da yapılabilir.

    >> [1, 2, 3] * 2
    => [1, 2, 3, 1, 2, 3]



    -- Array elemanlarına erişmek

    Array elemanlarına köşeli parantez içinde index değerlerini kullanarak erişirsiniz, index numaraları sıfırdan başlar.

    >> %w(a b c)[0]
    => "a"
    >> %w(a b c)[1]
    => "b"


    Range tanımları kullanarak array elemanlarından kesit alabilirsiniz. 

    >> %w(a b c d)[1..2]
    => ["b", "c"]   # 1 ve 2 indexliler dahil tüm aralık
    >> %w(a b c d)[1...2]  # 2 indexli aralık dışında kalır
    => ["b"]

    Bu işlemler yeni array oluşturur, orjinal array elemanları etkilenmez. Ruby'de negatif array indexleri de desteklenir.

    >> %w(a b c)[-1]
    => "c"
    >> %w(a b c)[-2]
    => "b"

    Negatif ve pozitif indexleri karışık kullanmak da mümkün.

    >> %w(a b c d e)[1...-1]
    => ["b", "c", "d"]


    diğer yararlı metodlar

    first metodu ile array'in ilk elemanına erişilir.

    >> [1, 2, 3, 4].first
    => 1


    first(n) ile ilk n sayıda elemana erişilir.

    >> [1, 2, 3, 4].first(2)
    => [1, 2]


    last ve last(n) ile de sondan itibaren elemanlara erişilir.

    >> [1, 2, 3, 4].last
    => 4
    >> [1, 2, 3, 4].last(2)
    => [3, 4]


    sample metodu ile array içinde rastgele bir elemana erişilir.

    >> [1, 2, 3, 4].sample
    => 4
    >> [1, 2, 3, 4].sample
    => 2


    veya sample(n)

    >> [1, 2, 3, 4].sample(2)
    => [2, 4]
    >> [1, 2, 3, 4].sample(2)
    => [1, 2]



    -- Değer ifadesi ile array oluşturma

    Bir array, elemanları köşeli parantez içinde ([ ]) verilerek tanımlanabilir.

    arr = [1, 2, 3, 4]


    Array bir nesneler dizisidir, içerisinde değişik veri tiplerinde elemanlar olabilir.

    arr = [1, 'b', nil, [3, 4]]



    -- Array elemanlarını ayrıştırmak

    Bir array elemanlarını ayrıştırmak için çoklu değişken ataması yapılabilir. 

    arr = [1, 2, 3]
    a = arr[0]
    b = arr[1]
    c = arr[2]
    # ya da aynı iş için çoklu atatma
    a, b, c = arr # a=1 , b=2 ve c=3
    a, b = arr # a=1 ve b=2


    Değişkenin birinin önüne yıldız operatörü ( * ) koymak o değişkene diğer değişkenlere atanmayan tüm elemanları saklar.

    a, *b = arr       # a = 1; b = [2, 3]
    a, *b, c = arr    # a = 1; b = [2]; c = 3
    a, b, c, *d = arr # a = 1; b = 2; c = 3; d = []
    a, *b, *c = arr   # SyntaxError: unexpected *


    Ayrıştırma güvenli bir işlemdir ve asla hata vermez, [ ] yapısıyla sınırlar dışında bir index'e erişmeye çalışıp eleman bulunamadığında nil değer verilir. 

    arr[9000]           # => nil
    a, b, c, d = arr    # a = 1; b = 2; c = 3; d = nil


    Ayrıştırma işlemi array olmayan nesnelere uygulandığında otomatik olarak o nesnenin to_ary metodu çağrılır. Bu metodu kendi veri tiplerinize de uyarlayarak verilerinizin ayrıştırılabilir olmasını sağlayabilirsiniz.

    class Foo
        def to_ary
            [1, 2]
        end
    end
    a, b = Foo.new # a = 1; b = 2


    Eğer ayrıştırılacak nesne to_ary metoduna cevap vermiyorsa, tek elemanlı bir array varmış gibi davranır.

    >> 1.respond_to? :to_ary
    => false
    >> a, b = 1     # a = 1; b = nil


    Ayrıştırma işlemi parantezler yardımıyla iç içe de yapılabilir. Parantez içindeki ayrıştırma ifadesi aslında oraya konmasaydı karşı gelecek tek bir değerin yerini alır.

    arr = [1, [2, 3, 4], 5, 6]
    a, (b, *c), *d = arr # a = 1; b = 2; c = [3, 4]; d = [5, 6]
    #   ^^^^^

    Biraz ayrıntılı düşünürsek.

    arr = [1, [2, 3, 4], 5, 6]
    a, x, *d = arr
    b, *c = x

    x değişkenine gelen değer (b, *c) olarak ayrıştırılıyor.

    Aslında herhangi bir ayrıştırma ifadesi parantez içinde yazılabilir. En üst seviyede bu opsiyoneldir.

    a, b = [1, 2]
    (a, b) = [1, 2] # aynı şey


    Ayrıştırma paterni tek bir ifade içeriyorsa parantez içinde yazılmaz.

    (a) = [1]           # SyntaxError
    a, (b) = [1, [2]]   # SyntaxError


    Ayrıştırma ifadesi eşitliğinin sağ tarafında bir array değer ifadesi varsa üst seviye köşeli parantezler gözardı edilebilir.

    a, b = [1, 2]
    a, b =  1, 2  # tamamen aynı şey

    Buna paralel atama denir ve arkaplanda tamamen aynı işlemi yapar. Bu değişken içeriklerini harici bir geçici değişken kullanmadan değiştirmek için çok etkili bir yoldur. 

    t = a; a = b; b = t # sıkıcı yöntem
    a, b = b, a         # Ruby yöntem
    (a, b) = [b, a]     # ...ve nasıl çalıştığı

    Atama yapılırken eşit işaretinin sağıdaki değer ayrıca hesaplanır ve sonra atama yapılır. Bu sayede aynı değişken isimleri kullanılabilir. 



    -- Array'lerde bileşim, kesişim ve fark

    İki tane array olsun.

    x = [5, 5, 1, 3]
    y = [5, 2, 4, 3]


    Bileşim operatörü ( | ) her iki array'de olan elemanları aynı olanları elimine ederek birleştirir.

    >> x | y
    => [5, 1, 3, 2, 4]


    Kesişim operatörü ( & ) her iki array'de de mevcut olan elemanları bulur.

    >> x & y
    => [5, 3]


    Fark operatörü ( - ) birinci array'de olup ikicide olmayan elemanları bulur.

    >> x - y
    => [1]



    -- İki boyutlu array

    Array::new metodunu kullanarak her elemanda yeni bir array olacak şekilde bir yapı tanımlayabilirsiniz.

    3x4 boyutlarında bir array'i değerler sıfır olacak şekilde tanımlamak istersek.

    >> arr = Array.new(3) { Array.new(4) { 0 } }
    => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]


    Bu iki boyutlu array elemanlarına okma ve yazma şöyle yapılır:

    >> arr[2][3] = 2
    => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 2]]

    Dıştaki array'in 2 indexli elemanı olan array'in 3 indexli elemanı.

    >> x = arr[2][3]
    => 2


    -- inject ve reduce

    inject ve reduce aynı şey için iki farklı isim. Argümanında 2 argümanı olan bir kod bloğu alır ve bu bloğu tüm eleman çiftlerine iterasyonla uygular. Bunu yaparken ilk değer olarak argümanda verilen değerle başlar. Örnek

    >> [1,2,3].reduce(0) {|a,b| a + b}
    => 6
    # ilk tarama a=0 ; b=1(ilk eleman)
    # ikinci tarama a=1(önceki tarama sonucu); b=2
    # üçüncü tarama a=3(önceki tarama sonucu); b=3


    Başlangıç değerini farklı verirsek.

    >> [1,2,3].reduce(5) {|a,b| a + b}
    => 11
    # ilk tarama a=5 ; b=1(ilk eleman)
    # ikinci tarama a=6(önceki tarama sonucu); b=2
    # üçüncü tarama a=8(önceki tarama sonucu); b=3


    Başlangıç değeri default 0'dır, vermesek de olur.

    >> [1,2,3].reduce {|a,b| a + b}
    => 6


    Kod bloğu içinde tek bir işlem yapıldığı için Ruby'ye sadece bu işlemi (metodu) sembol olarak bildirsek , o ne istediğimizi anlar.

    >> [1,2,3].reduce(0, :+)
    => 6

    >> [1,2,3].reduce(5, :+)
    => 11

    Sıfırdan başlarsak argüman vermeyebiliriz.

    >> [1,2,3].reduce(:+)
    => 6



    -- Array'lerde filtreleme

    Bazen bir ihtiyacımızı karşılamak amacıyla belli koşullara uyan array elemanlarına işlem yapmak isteyebiliriz. 

    -- -- select metodu

    Bu deyim belli koşulları karşılayan elemanları bulur.

    array = [1, 2, 3, 4, 5, 6]
    array.select { |number| number > 3 } # => [4, 5, 6]


    -- -- reject metodu

    Bu deyim belli koşulları karşılamayan elemanları bulur.

    array = [1, 2, 3, 4, 5, 6]
    array.reject { |number| number > 3 } # => [1, 2, 3]


    reject ve select metodları bir array döndüğü için zincirleme kullanılabilirler.

    array = [1, 2, 3, 4, 5, 6]
    array.select { |number| number > 3 }.reject { |number| number < 5 }
      # => [5, 6]

    Parantezler olmadan Ruby yorumlayıcı bu satırı nasıl çözdü merak ediyorum.



    -- Array'ler ve yıldız operatörü

    Yıldız operatörü ( * ) Ruby'de değişkenleri ve array'leri açmak için kullanılabilir. Böylece metodlara bağımsız argümanlar (ya da çoklu argüman) göndermek için kullanılabilir. 

    Bu kullanımı örneğin bir nesneyi array içine konmuş şekle dönüştürme amaçlı kullanabiliriz.

    def array_olarak_paketle(değer)
      [*değer]
    end

    array_olarak_paketle(1)
    #> [1]

    array_olarak_paketle([1, 2, 3])
    #> [1, 2, 3]

    array_olarak_paketle(nil)
    #> []

    Bu örnekte array_olarak_paketle metodu sadece bir parametre alır değer. Eğer değer bir array'se elemanlarına ayrılır ve yine bir array içinde toplanır. 

    Eğer değer tek bir nesneyse tek elemanı bu nesne olan bir array oluşturulur.

    Eğer değer, nil ise boş bir array oluşturulur.

    Yıldız operatörü metod parametresi tanımlarken bazen çok işimize yarar. Onu kullanarak tanımladığımız bir parametreye metod çağrılırken nil, tek bir değer, bir array ya da çoklu değer de verebiliriz.

    def listele(*değerler)
      değerler.each do |değer|
        # değer ile bir şeyler yap
        puts değer
      end
    end

    listele 100         # tek değer
    #> 100

    listele [100, 200]  # array değer
    #> 100
    #> 200

    listele 100, 200, 300  # çok değer
    #> 100
    #> 200
    #> 300

    listele nil
    # hiçbir şey yazmaz sadece alt satıra geçer

    listele
    # bu tamamen hiçbir şey yazmaz



    -- Array'lerde map metodu

    Array#map metodu arkasından verilen kod bloğunu array'in her elemanı için çalıştırarak iterasyon yapar, ve sonuçları toplar.

    >> [1, 2, 3].map { |i| i * 3 }
    => [3, 6, 9]

    >> ['1', '2', '3', '4', '5'].map { |i| i.to_i }
    # ya da blokta tek işlem olduğu için
    >> ['1', '2', '3', '4', '5'].map &:to_i
    => [1, 2, 3, 4, 5]

    Orjinal array değiştirilmez yeni bir array aynı elemanların işlendiği sırayla dönen değer olarak üretilir. Eğer orjinal array'i değiştirmek istiyorsanız map! metodunu kullanınız.

    map metodunda tüm elemanlara aynı metodu uygulayabilir ya da her biri için aynı Proc rutinini uygulayabilirsiniz.

    # to_i metodunu tüm elemanlarda çağır
    %w(1 2 3 4 5 6 7 8 9 10).map(&:to_i)
    # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    # usintüm elemanlar için proc (lambda) çağırmak
    %w(1 2 3 4 5 6 7 8 9 10).map(&->(i){ i.to_i * 2})
    # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

    map ve collect metodları eşdeğerdir.

    & operatörü bir Proc nesnesini kod bloğuna çevirir, &:to_i ifadesinde to_i metodu önce otomatik olarak to_proc metodu ile Proc nesnesine dönüştürülerek kullanılır. 

    İkinci örnekteki Proc nesnesi üretme kodu genellikle daha uzun işlemler yapacağımızda kullanılır. Proc nesnesi dediğimize göre de bir değişkene konabilir. Örneğin:

    a = Proc.new do |x|
      b = x.to_i
      b * 2
    end
    %w(1 2 3 4 5 6 7 8 9 10).map(&a)

    ya da 

    a = ->(x) do
      b = x.to_i
      b * 2
    end
    %w(1 2 3 4 5 6 7 8 9 10).map(&a)

    gibi. Böylece map yanına uzun bloklar koymak zorunda kalmazsınız. 



    -- Çok boyutlu array'i tek boyutlu düz array haline getirmek

    Oldu da gerekirse bu işlem için flatten metodunu kullanırız.

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



    -- Array elemanlarının eşit olanlarından kurtulmak

    Bir array'in elemanlarını tekrarlananlar olmadan elde etmek istersek uniq metodunu kullanırız.

    >> a = [1, 1, 2, 3, 4, 4, 5]
    >> a.uniq
    => [1, 2, 3, 4, 5]

    Array içindeki tekrarlanan elemanları yok etmek istersek direk array'e işlem yapan uniq! metodunu kullanırız.

    >> a = [1, 1, 2, 3, 4, 4, 5]
    >> a.uniq
    => [1, 2, 3, 4, 5]
    >> a
    => [1, 1, 2, 3, 4, 4, 5] # a değerini koruyor
    >> a.uniq!
    => [1, 2, 3, 4, 5]
    >> a
    => [1, 2, 3, 4, 5] # a değişti



    -- Bir array'in tüm kombinasyon ve permutasyonlarını bulmak

    Array'in tüm permutasyonlarını bulmak için permutation metodu kullanılır, bu bize bir Enumarator nesnesi döner.

    >> [1, 2, 3].permutation
    => #<Enumerator: ...>
    >> [1, 2, 3].permutation.map &:to_s
    => ["[1, 2, 3]", "[1, 3, 2]", "[2, 1, 3]", "[2, 3, 1]", "[3, 1, 2]", "[3, 2, 1]"]
    >> [1, 2, 3].permutation.to_a
    => [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

    İçinde ne var olduğuna erişmek için map ile işlem yapabilir ya da to_a metodu ile sonuçları iki boyutlu array olarak alabiliriz.

    2'li permutasyonlarını bulmak için, 2 değerini argüman olarak veririz.

    >> [1, 2, 3].permutation(2).to_a
    => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]

    4'lü istesek boş sonuç gelir.

    >> [1, 2, 3].permutation(4).to_a
    => []


    Kombinasyon için combination metodu kullanılır. Bilindiği gibi kombinasyonlarda sıralama gereği yoktur, yani [1, 2, 3] ile [3, 2, 1] aynıdır.

    >> [1, 2, 3].combination(3).to_a
    => [[1, 2, 3]]
    >> [1, 2, 3].combination(2).to_a
    => [[1, 2], [1, 3], [2, 3]]
    >> [1, 2, 3].combination(1).to_a
    => [[1], [2], [3]]

    Yine 2 boyutlu array'ler dönüyor. combination metodunun bir farkı , argüman vermek zorundasınız.

    repeated_combination ve repeated_permutation metodları da benzer işler yaparlar ancak bulunan olasılıklarda  aynı elemanlar defalarca kullanılabilir olarak düşünülür.

    >> [1, 2, 3].repeated_combination(3).to_a
    =>
    [[1, 1, 1],
     [1, 1, 2],
     [1, 1, 3],
     [1, 2, 2],
     [1, 2, 3],
     [1, 3, 3],
     [2, 2, 2],
     [2, 2, 3],
     [2, 3, 3],
     [3, 3, 3]]

    gibi. Sanki şifre çözme programı için yapılmış.

    >> [0,1,2,3,4,5,6,7,8,9].repeated_permutation(4).to_a.length                                  
    => 10000

    Bana sorsanız ben de derdim 0000'dan 9999'a kadar 10 bin olasılık vardır. Ama bunlar örnek, çok daha karmaşık array'ler üzerinde işlem yaparken lazım bu metodlar.



    -- compact ile array içinde nil olan elemanları uzaklaştırmak

    Bir array içindeki nil olan değerleri silmek için Array#compact ya da Array#compact! metodları kullanılır. 

    >> array = [ 1, nil, 'selam', nil, '5', 33]
    >> array.compact
    => [ 1, 'selam', '5', 33]

    # bu metod yeni bir array oluşturup onu döner
    >> array
    => [1, nil, "selam", nil, "5", 33]

    # Eğer orjinali değiştirmek isterseniz
    # ya dönen değeri tekrar atama yaparsınız
    >> array = array.compact
    >> array                                                                                    
    => [1, "selam", "5", 33]

    # yada metodun 'bang' versiyonunu kullanırsınız
    >> array = [ 1, nil, 'selam', nil, '5', 33]                                                  
    >> array.compact!                                                                            
    >> array                                                                                      
    => [1, "selam", "5", 33]

    Son olarak bir not compact! metodlarını içinde nil değerli eleman olmayan bir array nesnesinde çağırırsanız, sonuç nil olur ama orjinali değiştirmez. 

    >> array = [1, 2, :foo, "boo"]                                                                
    => [1, 2, :foo, "boo"]
    >> array.compact                                                                              
    => [1, 2, :foo, "boo"]
    >> array                                                                                      
    => [1, 2, :foo, "boo"]
    >> array.compact!                                                                            
    => nil
    >> array                                                                                      
    => [1, 2, :foo, "boo"]



    -- Sıralı sayı ya da harflerden array oluşturmak

    Bu bir Range nesnesine Enumerable#to_a metodu uygulayarak yapılabilir. 

    >> (1..10).to_a
    => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    (a..b) notasyonu iki uçtaki a ve b sayıları dahil tüm sayılar için kullanılır, sondaki sayıyı dışarıda bırakmak için üç noktalı (a...b) notasyonu kullanılır.

    >> bir_range = 1...5
    >> bir_range.to_a
    => [1, 2, 3, 4]

    ya da harfler için

    >> ('a'..'f').to_a
    => ["a", "b", "c", "d", "e", "f"]
    >> ('a'...'f').to_a
    => ["a", "b", "c", "d", "e"]

    Türkçe karakterlerde aynı işi yapmanın hazır bir yolunu bulamadım kendim bir şeyler karaladım.

    ta = %w(a b c ç d e f g ğ h ı i j k l m n o ö p r s ş t u ü v y z)
    def ta.range ilk, son, dahil=true
      if dahil
        self[self.index(ilk)..self.index(son)]
      else
        self[self.index(ilk)..self.index(son)-1]
      end
    end
    p ta.range("b", "ı")
    # => ["b", "c", "ç", "d", "e", "f", "g", "ğ", "h", "ı"]
    p ta.range("b", "ı", false)
    # => ["b", "c", "ç", "d", "e", "f", "g", "ğ", "h"]



    -- Sayılardan array oluşturmak

    Sayılardan array oluşturmanın normal yolu 

    sayılar = [1, 2, 3, 4, 5]


    Range nesneleri de sıralı sayılardan array oluşturmak amaçlı kullanılır.

    >> sayılar = Array(1..10)
    => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    ya da 

    >> sayılar = (1..10).to_a
    => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


    Range sayılarda istediğimiz koşulları empoze etmek için step ve map metodları kullanabiliriz.

    >> tek_sayılar = (1..10).step(2).to_a
    => [1, 3, 5, 7, 9]

    >> çift_sayılar = 2.step(10, 2).to_a
    => [2, 4, 6, 8, 10]

    >> kareler = (1..10).map { |sayı| sayı * sayı }
    => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]



    -- Herhangi bir nesneyi array'e dönüştürmek

    Kernel#Array fonksiyonu ile diğer nesneler array'e dönüştürülebilir.

    >> Array('birşey')
    => ["birşey"]

    >> Array([2, 1, 5])
    => [2, 1, 5]

    >> Array(1)
    => [1]

    >> Array(2..4)
    => [2, 3, 4]

    >> Array([])
    => []

    >> Array(nil)
    => []


    Diyelim string_olarak_birleştir adında bir metod yazdınız.

    def string_olarak_birleştir(arg)
      if arg.instance_of?(Array)
        arg.join(',')
      elsif arg.instance_of?(Range)
        arg.to_a.join(',')
      else
        arg.to_s
      end
    end

    string_olarak_birleştir('birşey')    #=> "birşey"
    string_olarak_birleştir([2, 1, 5])   #=> "2,1,5"
    string_olarak_birleştir(1)           #=> "1"
    string_olarak_birleştir(2..4)        #=> "2,3,4"
    string_olarak_birleştir([])          #=> ""
    string_olarak_birleştir(nil)         #=> ""

    bu metodu basitçe şöyle yazabilirsiniz.

    def string_olarak_birleştir(arg)
      Array(arg).join(',')
    end


    Şimdilik bu kadar yeterli, bir sonraki bölümde sınıflara geçeceğiz nasipse. 

    Kalın sağlıcakla..







    Hiç yorum yok:

    Yorum Gönder