Array
Kompakt, sıralı objeler içeren bir türü taşıcıyı nesnedir Array’ler. Neredeyse içinde her tür Ruby objesini taşıyabilir. (String, Integer, Fixnum, Hash, Symbol hatta başka Array’ler vs...)
Arka arkaya sıralanmış kutucuklar düşünün, her kutucuğun bir index numarası olduğunu hayal edin. Bu indeksleme işi otomatik olarak oluyor. Diziye her eleman eklediğinizde (Eğer kendiniz indeks numarası atamadıysanız) yeni indeks bir artarak devam ediyor. Zero Indexed yani ilk eleman 0.eleman oluyor.
Aynı String’deki gibi negatif indeks değerleri ile tersten erişim
sağlıyorsunuz. Yani ilk eleman array[0]
ve son eleman array[-1]
gibi...
Array oluşturmak için;
a = [] # Ya bu şekilde
a.class # => Array
b = Array.new # => Ya da bu şekilde
b.class # => Array
kullanabilirsiniz. Keza a = [1, 2, 3]
dediğinizde de Array’i hem tanımlamış
hem de elemanlarını belirlemiş olursunuz.
Array’i initialize ederken yani ilk kez oluştururken büyüklüğünü de verebilirsiniz.
a = Array.new(5) # içinde 5 eleman taşıyacak Array oluştur
a # => [nil, nil, nil, nil, nil]
Hatta, default değer bile atarsınız:
aylar = Array.new(12, "ay") # 12 eleman olsun ve hepsi "ay" olsun
aylar # => ["ay", "ay", "ay", "ay", "ay", "ay", "ay", "ay", "ay", "ay", "ay", "ay"]
Ruby’de her nesnenin bir ID’si ve HASH değeri vardır.
[1, 2, 3].hash # => 3384159031637530117
[1, 2, 3].__id__ # => 70147646473880
Block kabul ettiği için;
dizi = Array.new(10) { |eleman| eleman = eleman * 4 }
dizi # => [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]
# ya da aynı kodu
dizi = Array.new(10) do |eleman|
eleman = eleman * 4
end
dizi # => [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]
şeklinde de kullanabilirsiniz. Neticede Array’in initialize method’una parametre geçmiş oluyoruz:
aylar = Array.[]("oca", "şub", "mar", "nis", "may", "haz", "tem", "ağu", "eyl", "eki", "kas", "ara")
aylar # => ["oca", "şub", "mar", "nis", "may", "haz", "tem", "ağu", "eyl", "eki", "kas", "ara"]
Yani: aylar = Array.[](param, param, param)
gibi.
Başka nasıl üretiriz? Sayılardan oluşan bir dizi lazım olsa; Örneğin 1984 ile 2000 arasındaki yıllar lazım olsa;
years = Array(1984..2000)
years # => [1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000]
Bir Array içinde farklı türden elemanlar olabilir;
a = ["Hello", :word, 2014, 3.14] # içinde String, Symbol, Fixnum ve Float var!
a # => ["Hello", :word, 2014, 3.14]
Array içindeki elemanlar sıralı bir şekilde dururlar. Bu sıraya Index
denir. 0’dan başlar. Yani ilk eleman demek Array’in 0.elemanı demektir.
İsteğimiz elemanı almak için ya Array[index]
ya da Array.fetch(index)
yöntemlerini kullanabiliriz.
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a[0] # => "Uğur"
a.fetch(0) # => "Uğur"
a[4] # => nil
a.fetch(4, "Hatalı Index") # => "Hatalı Index"
a = [1, 2, 3, 4] # İlk N elemanı al
a.take(2) # => [1, 2]
a.drop(2) # => [3, 4] # take’in tersi... İlk 2 haricini al
Örnekte a[4]
dediğimiz zaman, olmayan index’li elemanı almaya çalışıyor ve
eleman olmadığı için nil
geri alıyoruz. fetch
kullanarak hata kontrolü de
yapmış oluyoruz. nil
yerine belirlediğimiz hata mesajını dönmüş oluyoruz.
values_at
method’u ile ilgili index ya da index’lerdeki elemanları
alabiliriz, keza at
de benzer işe yarar.
isimler = ["Uğur", "Ömer", "Yeşim", "Ezel", "Eren"]
isimler.values_at(0) # => ["Uğur"]
isimler.values_at(1, 2) # => ["Ömer", "Yeşim"]
["a", "b", "c", "d", "e"].at(1) # => "b"
["a", "b", "c", "d", "e"].at(-1) # => "e"
rindex
ile sağdan hizalı index’e göre elemana ulaşıyoruz:
a = [ "a", "b", "b", "b", "c" ]
a.rindex("b") # => 3 # 3 tane b var, en sağdaki son b’yi verdi!
a.rindex("z") # => nil
Keza "acaba Array’in ne gibi method’ları var?" dersek; hemen methods
özelliği ile bakabiliriz. Karıştırmamamız gereken önemli bir konu var.
Detayını Class konusunda göreceğiz ama yeri gelmişken, Array’in Class
Method’ları ve Instance Method’ları var.
Array.methods
dediğimizde Kernel’dan gelen Array objesinin yani
Class’ının method’larını görürüz. Eğer Array.new.methods
dersek,
Array’den türettiğimiz instance’a ait method’ları görürüz.
Yani a = []
dediğimizde, aslında Array’den bir instance çıkartmış
oluyoruz. Az önce Array.[](...)
olarak yaptığımız şey de aslında Class
method’u çağırmak.
Class Method’ları
Array.methods # => [:[], :try_convert, :allocate, :new, :superclass, :freeze, :===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :inspect, :included_modules, :include?, :name, :ancestors, :instance_methods, :public_instance_methods, :protected_instance_methods, :private_instance_methods, :constants, :const_get, :const_set, :const_defined?, :const_missing, :class_variables, :remove_class_variable, :class_variable_get, :class_variable_set, :class_variable_defined?, :public_constant, :private_constant, :singleton_class?, :include, :prepend, :module_exec, :class_exec, :module_eval, :class_eval, :method_defined?, :public_method_defined?, :private_method_defined?, :protected_method_defined?, :public_class_method, :private_class_method, :autoload, :autoload?, :instance_method, :public_instance_method, :nil?, :=~, :!~, :eql?, :hash, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
Bu method’ların bir kısmı Enumerable sınıfından gelen method’lardır. Ruby, Module yapısı kullandığı için ortak kullanılan method’lar modül eklemelerinden gelmektedir. Class konusunda detayları göreceğiz.
Bu kısımdan en fazla kullanacağımız []
ve new
method’ları olacaktır.
Instance Method’ları
En çok kullanacağımız method’larsa;
Array.new.methods # => [:inspect, :to_s, :to_a, :to_h, :to_ary, :frozen?, :==, :eql?, :hash, :[], :[]=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, :<=>, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :lazy, :nil?, :===, :=~, :!~, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
Aynı String’deki gibi, şu Array’in bir röntgenini çekelim:
Array.class # => Class
Array.class.superclass # => Module
Array.class.superclass.superclass # => Object
Array.class.superclass.superclass.superclass # => BasicObject
Array.class.superclass.superclass.superclass.superclass # => nil
Array’in bir üst objesi ne? Module Yine Class konusunda göreceğiz diyeceğim ve siz bana kızacaksınız :) Ruby’de bir Class en fazla başka bir Class’dan türeyebilir. Örneğin Python’da bir Class N TANE Class’tan inherit olabilir (Miras alabilir, türeyebilir)
Ruby, bu sorunu Module yapısıyla çözüyor. Bu mantıkla aslında ortaklaşa kullanılan Kernel modülleri yardımıyla, ortak kullanılacak method’lar bu modüllerin Include edilmesiyle ilgili yerlere dağıtılıyor.
Acaba Array’de hangi modüller var?
Array.included_modules # => [Enumerable, Kernel]
Bu bakımdan Array, Hash gibi nesnelerde benzer ortak method’lar görmek mümkün.
length veya count
Array’in boyu / içinde kaç eleman olduğu ile ilgili bilgiyi almak için kullanılır.
[1, 2, 3, 4].length # => 4
[1, 2, 3, 4].count # => 4
empty?
Array acaba boşmu? İçinde hiç eleman var mı?
[1, 2, 3, 4].empty? # => false
[].empty? # => true
eql?, ==, ===
Eşitlik kontrolü içindir. Eğer karşılığı aynı cinsse ve birebir aynı
elemanlara sahipse true
döner.
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.eql?(["Yeşim", "Ezel", "Ömer", "Uğur"]) # => false
a.eql?([]) # => false
a.eql?(["Uğur", "Yeşim", "Ezel", "Ömer"]) # => true
==
Generic Equality yani genel eşitlik kontrolü yani hepimizin bildiği
kontrol, ===
ise Case Equality yani a === b
ifadesinde a,
b’nin subseti mi? demek olur. Örnek verelim:
5.class.superclass # => Integer
Integer === 5 # => true
# 5, Integer subsetinde...
Integer.class # => Class
Integer.class.superclass # => Module
Integer.class.superclass.superclass # => Object
Integer.class.superclass.superclass.superclass # => BasicObject
Integer.class.superclass.superclass.superclass.superclass # => nil
# Integer, 5’in subsetinde değil.
5 === Integer # => false
include? ve member?
Acaba verdiğim eleman Array’in içinde mi? Verdiğim eleman bu dizinin üyesi mi?
[1, 2, 3, 4].include?(3) # => true
[1, 2, 3, 4].member?(1) # => true
[1, 2, 3, 4].member?(5) # => false
["Uğur", "Ezel", "Yeşim"].include?("Uğur") # => true
["Uğur", "Ezel", "Yeşim"].include?("Ömer") # => false
array & başka_bir_array
İki dizide de kullanın ortak elemanları alır yeni Array döner:
a = [1, 2, 3, 4]
b = [3, 1, 10, 22]
a & b # => [1, 3]
array * int [ya da] array * str
a = ["a", "b", "c"]
a * 5 # => ["a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c"]
a * "-vigo-" # => "a-vigo-b-vigo-c"
**\***
çaparak 3 elemanlı a
Array’inden sanki birleştirilmiş 15
elemanlı yeni bir Array oluşturduk. String ile çarpınca da aslında join
methodu ile Array’den String yaptık ve birleştirici olarak -vigo- metni
kullandık!
array + başka_array
İki Array’i toplar ve yeni Array döner:
a = ["Uğur", "Yeşim", "Ezel"]
b = ["Ömer"]
a + b # => ["Uğur", "Yeşim", "Ezel", "Ömer"]
array - başka_array
Array’ler arasındaki farkı Array olarak bulmak:
a = ["Uğur", "Yeşim", "Ezel"]
b = ["Uğur", "Yeşim"]
a - b # => ["Ezel"] # a’da olab b elemanları kayboldu
array | başka_array
İki Array’i unique (tekil) elemanlar olarak birleştirdi. Aynı eleman varsa bunlardan birini aldı:
a = ["Uğur", "Yeşim", "Ezel"]
b = ["Uğur", "Ömer"]
a | b # => ["Uğur", "Yeşim", "Ezel", "Ömer"]
array << nesne ya da push
Array’in sonuna eleman eklemek için kullanılır.
a = ["Uğur", "Yeşim", "Ezel"]
a << "Ömer" # => ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.push("Eren") # => ["Uğur", "Yeşim", "Ezel", "Ömer", "Eren"]
Keza zincirleme çağrı da yapabilirsiniz:
a.push("Tunç").push("Suat") # => ["Uğur", "Yeşim", "Ezel", "Ömer", "Eren", "Tunç", "Suat"]
concat
Array sonuna Array eklemek için kullanılır.
a = [1, 2, 3]
a.concat([4, 5, 6])
a # => [1, 2, 3, 4, 5, 6]
join
Array elemanlarını birleştirip String’e çevirmeye yarar. Eğer parametre verirsek aradaki birleştiriciyi de belirlemiş oluruz.
["Commodore 64", "Amiga", "Sinclair", "Amstrad"].join # => "Commodore 64AmigaSinclairAmstrad"
["Commodore 64", "Amiga", "Sinclair", "Amstrad"].join(" , ") # => "Commodore 64 , Amiga , Sinclair , Amstrad"
unshift
Array’in başına eleman eklemek için kullanılır.
a = ["Uğur", "Yeşim", "Ezel"]
a.unshift("Ömer") # => ["Ömer", "Uğur", "Yeşim", "Ezel"]
insert
Array’de istediğiniz bir noktaya eleman eklemek için kullanılır. İlk parametre index diğer parametre/ler de eklenecek eleman/lar.
a = ["Uğur", "Yeşim", "Ezel"]
a.insert(1, "Ömer") # => ["Uğur", "Ömer", "Yeşim", "Ezel"]
a.insert(1, "Ahmet", "Ece", "Eren") # => ["Uğur", "Ahmet", "Ece", "Eren", "Ömer", "Yeşim", "Ezel"]
replace
Array’in içini, diğer Array’le değiştirir. Aslında Array’i başka bir Array’e eşitlemek gibidir. Eleman sayısının eşit olup olmaması hiç önemli değildir.
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.replace(["Foo", "Bar"]) # => ["Foo", "Bar"]
a # => ["Foo", "Bar"]
array <=> başka_array
Spaceship operatöründen bahsetmiştik. Array’ler arasında karşılaştırma yapmayı sağlar.
[1, 2, 3, 4] <=> [1, 2, 3, 4] # => 0 # Eşit
[1, 2, 3, 4] <=> [1, 2, 3] # => 1 # İlk değer büyük
[1, 2, 3] <=> [1, 2, 3, 4] # => -1 # İlk değer küçük
pop, shift, delete, delete_at, delete_if
Son elemanı çıkartmak için pop ilk elemanı çıkartmak için shift kullanılır. Herhangi bir elemanı çıkartmak için delete, belirli bir index’deki elemanı çıkartmak için delete_at kullanılır.
a = ["Uğur", "Ömer", "Yeşim", "Ezel", "Eren"]
a.pop # => "Eren"
a # => ["Uğur", "Ömer", "Yeşim", "Ezel"]
a.shift # => "Uğur"
a # => ["Ömer", "Yeşim", "Ezel"]
a.delete("Ömer") # => "Ömer"
a # => ["Yeşim", "Ezel"]
a.delete_at(1) # => "Ezel"
a # => ["Yeşim"]
# not 50’den küçükse sil :)
notlar = [40, 45, 53, 70, 99, 65]
notlar.delete_if { |notu| notu < 50 } # => [53, 70, 99, 65]
pop’a parametre geçersek son n taneyi uçurmuş oluruz:
a = ["Uğur", "Ömer", "Yeşim", "Ezel", "Eren"]
a.pop(2) # => ["Ezel", "Eren"]
a # => ["Uğur", "Ömer", "Yeşim"]
compact ve uniq
nil
elemanları uçurmak için compact, duplike elemanları tekil hale
getirmek için uniq kullanılır.
["a", 1, nil, 2, nil, "b", 1, "a"].compact # => ["a", 1, 2, "b", 1, "a"]
["a", 1, nil, 2, nil, "b", 1, "a"].uniq # => ["a", 1, nil, 2, "b"]
["a", 1, nil, 2, nil, "b", 1, "a"].compact.uniq # => ["a", 1, 2, "b"]
array == başka_array
İki Array nitelik ve nicelik olarak birbirine eşit mi?
[1, 2, 3, 4] == [1, 2, 3, 4] # => true
[1, 2, 3, 4] == ["1", 2, 3, 4] # => false
[1, 2, 3, 4] == [1, 2, 3] # => false
assoc ve rassoc
Elemanları Array olan bir Array içinde, ilk değere göre yakalama yapmaya yarar.
a = ["renkler", "kırmızı", "sarı", "mavi"]
b = ["harfler", "a", "b", "c"]
c = "foo"
t = [a, b, c]
t # => [["renkler", "kırmızı", "sarı", "mavi"], ["harfler", "a", "b", "c"], "foo"]
t.assoc("renkler") # => ["renkler", "kırmızı", "sarı", "mavi"]
t.assoc("foo") # => nil
t.rassoc("kırmızı") # => ["renkler", "kırmızı", "sarı", "mavi"]
rassoc
ise ikinci elemanına bakar, yani "renkler" yerine "kırımızı"
kullanabiliriz:
slice(başlangıç, boy) ya da slice(aralık)
Array içinden kesip başka bir Array oluşturmak için kullanılır. başlangiç indeks’indeki eleman dahil olmak üzere, boy ya da aralık kadarını kes.
[1, 2, 3, 4].slice(0, 2) # => [1, 2] # 0.dan itibaren 2 tane
[1, 2, 3, 4].slice(2..4) # => [3, 4] # 2.den itibaren 2 tane
first ve last
Adından da anlaşılacağı gibi, Array’in ilk ve son elemanları için kullanılır:
a = [1, 2, 3, 4, 5]
a.first # => 1
a.last # => 5
Eğer parametre geçersek, ilk n ya da son n elemanları alabiliriz:
a = [1, 2, 3, 4, 5]
a.first(2) # => [1, 2]
a.last(2) # => [4, 5]
find (detect), find_all, index, find_index
find
ile blok içinde koşula uyan ilk Array elemanını, find_all
ile tümünü
alırız:
["Uğur", "Yeşim", "Ezel", "Ömer"].find { |n| n.length > 3 } # => "Uğur"
["Uğur", "Yeşim", "Ezel", "Ömer"].find_all { |n| n.length > 3 } # => ["Uğur", "Yeşim", "Ezel", "Ömer"]
detect
ile find
aynı işi yapar.
index
, find_index
ile elemanın index’ini buluruz:
["a", "b", "c", "d", "e"].index("e") # => 4
["Uğur", "Yeşim", "Ezel", "Ömer"].index("Ezel") # => 2
["Uğur", "Yeşim", "Ezel", "Ömer"].find_index("Ezel") # => 2
clear
Array’i temizlemek için kullanılır :)
a = [1, 2, 3]
a.clear # => []
a # => []
reverse
Array’i terse çevir.
a = [1, 2, 3, 4, 5]
a.reverse # => [5, 4, 3, 2, 1]
sample
Array’den random olarak eleman almaya yarar. Eğer parametre geçilirse geçilen adet kadar random eleman döner.
a = [1, 2, 3, 4, 5]
a.sample # => 3
a.sample(3) # => [5, 1, 3]
shuffle
Array’in içindeki elemanların index’lerini karıştırır :)
a = [1, 2, 3, 4, 5]
a.shuffle # => [5, 4, 1, 3, 2]
a.shuffle # => [1, 2, 3, 5, 4]
sort
Array içindeki elemanları <=>
mantığıyla sıralar.
a = [1, 4, 2, 3, 11, 5]
a.sort # => [1, 2, 3, 4, 5, 11]
b = ["a", "c", "b", "z", "d"]
b.sort # => ["a", "b", "c", "d", "z"]
fill
Array’in içini ilgili değerle doldurmak için kullanılır. İşlem sonucunda orijinal Array’in değeri değişir. Yani ne ile fill ettiyseniz Array artık o değerlerdedir.
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.fill("x") # => ["x", "x", "x", "x"] # tüm elemanları x yaptı
a # => ["x", "x", "x", "x"] # artık a’nın yeni değeri bu
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.fill("y", 2) # => ["Uğur", "Yeşim", "y", "y"] # 2.den itibaren y ile doldur
a = ["Uğur", "Yeşim", "Ezel", "Ömer"] # 2.den itibaren 1 tane doldur
a.fill("z", 2, 1) # => ["Uğur", "Yeşim", "z", "Ömer"]
Keza;
a = [1, 2, 3, 4, 5]
a.fill { |i| i * 5 } # => [0, 5, 10, 15, 20]
a # => [0, 5, 10, 15, 20]
şeklinde de kullanılır.
flatten
Array içinde Array elemanları varsa, tek harekette bunları düz tek bir Array haline getirebiliriz.
[1, 2, ["a", "b", :c], [66, [5.5, 3.1]]].flatten # => [1, 2, "a", "b", :c, 66, 5.5, 3.1]
rotate
Array elemanları kendi içinde kaydırır.
a = [1, 2, 3, 4, 5]
a.rotate # => [2, 3, 4, 5, 1] # 1 kaydırdı
a.rotate(2) # => [3, 4, 5, 1, 2] # 2 kaydırdı, ilk 2 elemanı sona koydu!
Varsayılan değer 1’dir.
zip
a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]
[1, 2, 3].zip(a, b) # => [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
[1, 2].zip(a, b) # => [[1, 4, 7], [2, 5, 8]]
a.zip([1, 2], [8]) # => [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
[1, 2, 3].zip(a, b)
işlemini yaparken, önce 0.elemanı yani 1’i aldı,
sonra a’nun 0.elemanını aldı, sonra da b’nin 0.elemanını aldı ve
paketledi : [1, 4, 7]
aynı işi 1. ve 2. elemanlar için yaptı.
[1, 2].zip(a, b)
yaparken, Array boyları eşit olmadığı için [1, 2]
sadece
2 elemanlı olduğu için bu işlemi 0. ve 1. elemanlar için yaptı.
Son örnekte index’e karşılık gelmediği için elemanlar nil
geldi!
transpose
Array içindeki Array’leri satır gibi düşünüp bunları sütuna çeviriyor gibi algılayabilirsiniz.
a = [[1, 2], [3, 4], [5, 6]]
a.transpose # => [[1, 3, 5], [2, 4, 6]]
# [
# [1, 2],
# [3, 4],
# [5, 6]
# ]
# -> [1, 3, 5], [2, 4, 5]
#
Tip Çeviricileri
to_a
ve to_ary
kendisini döner, asıl görevi eğer alt sınıftan çağrılmışsa,
yani Array’den türeyen başka bir Class’da kullanıldığında direk Array’e
dönüştürür.
["a", 1, "b", 2].to_a # => ["a", 1, "b", 2]
["a", 1, "b", 2].to_ary # => ["a", 1, "b", 2]
[["a", 1], ["b", 2]].to_h # => {"a"=>1, "b"=>2}
["a", 1, "b", 2].to_s # => "[\"a\", 1, \"b\", 2]"
["a", 1, "b", 2].inspect # => "[\"a\", 1, \"b\", 2]"
entries
de aynen to_a
gibi çalışır:
(1..3) # => 1..3
(1..3).entries # => [1, 2, 3]
(1..3).to_a # => [1, 2, 3]
grep
Aslında bu konuları Regular Expressions’da göreceğiz ama yeri gelmişken hızla değinelim. Array içinde elemanları Regex koşullarına göre filtreleyebiliyoruz:
(1..10).to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 2’den 5’e kadar (5 dahil)
(1..10).grep 2..5 # => [2, 3, 4, 5]
# sadece .com olan elemanları al
["a", "http://example.com", "b", "foo", "http://webbox.io"].grep(/^http.+\.com/) # => ["http://example.com"]
pack
Array’in içeriğini verilen direktife göre Binary String haline getirir. Uzunca bir direktif listesi var.
# A: String olarak işle, space karakteri kullan
# 5: Uzunluğu 5 karakter olsun
["a", "b", "c"].pack("A5A5A5") # => "a b c "
# Uzunluğu 5’ten büyük olan kesintiye uğradı
["ali", "burak", "cengiz"].pack("A5A5A5") # => "ali burakcengi"
# a: String olarak işle, null yani \x00 karakteri kullan
["a", "b", "c"].pack("a3a3a3") # => "a\x00\x00b\x00\x00c\x00\x00"
İterasyon ve Block Kullanımı
collect / map { |eleman| blok } → yeni_array
Blok içinde gelen kodu her elemana uygular, yeni Array döner:
a = [1, 2, 3, 4, 5]
a.collect { |i| i * 2 } # => [2, 4, 6, 8, 10]
a.collect { |i| "sayı #{i}" } # => ["sayı 1", "sayı 2", "sayı 3", "sayı 4", "sayı 5"]
map
de aynı işi yapar:
["Uğur", "Yeşim", "Ezel", "Ömer"].map { |isim| "İsim: #{isim}" } # => ["İsim: Uğur", "İsim: Yeşim", "İsim: Ezel", "İsim: Ömer"]
["Uğur", "Yeşim", "Ezel", "Ömer"].collect { |isim| "İsim: #{isim}" } # => ["İsim: Uğur", "İsim: Yeşim", "İsim: Ezel", "İsim: Ömer"]
select
Blok içinden gelen ifadenin true / false olmasına göre filtre yapar ve yeni Array döner:
[1, 2, 3, 10, 15, 20].select { |n| n % 2 == 0 } # => [2, 10, 20] # 2’ye tam bölünenler
[1, 2, "3", "ali", 15, 20].select { |n| n.is_a?(Fixnum) } # => [1, 2, 15, 20] # sadece sayılar
reject
select
in tersidir.
[1, 2, 3, 10, 15, 20].reject { |n| n % 2 == 0 } # => [1, 3, 15] # 2’ye tam bölülenleri at
[1, 2, "3", "ali", 15, 20].reject { |n| n.is_a?(Fixnum) } # => ["3", "ali"] # Sayı olanları at
keep_if
Blok içindeki ifade’den sadece false
dönenleri atar ve Array’in orjinal
değerini bozar, değiştirir.
a = [1, 2, 3, 10, 15, 20]
a.keep_if { |n| n % 2 == 0 } # => [2, 10, 20] # 2’ye bölünemeyenler false geldiği için düştüler.
a # => [2, 10, 20] # a artık bu!
combination(n) { |c| blok } → array
Matematikteki kombinasyon işlemidir. 1, 2 ve 3 sayılarının 2’li kombinasyonu:
a = [1, 2, 3]
a.combination(1).to_a # => [[1], [2], [3]]
a.combination(2).to_a # => [[1, 2], [1, 3], [2, 3]]
a.combination(2) { |c| puts "Olasıklar: #{c.join(" ve ")}" }
# Olasıklar: 1 ve 2
# Olasıklar: 1 ve 3
# Olasıklar: 2 ve 3
permutation
Aynı kombinasyon gibi, matematikteki permütasyon işlemidir.
[1, 2, 3].permutation.to_a # => [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
Eğer parametre geçersek kaçlı permütasyon olduğunu belirtiriz:
[1, 2, 3].permutation(1).to_a # => [[1], [2], [3]]
[1, 2, 3].permutation(2).to_a # => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
repeated_combination, repeated_permutation
combination
ile repeated_combination
arasındaki farkı örnekle görelim:
[1, 2, 3].combination(1).to_a # => [[1], [2], [3]]
[1, 2, 3].repeated_combination(1).to_a # => [[1], [2], [3]]
[1, 2, 3].combination(2).to_a # => [[1, 2], [1, 3], [2, 3]]
[1, 2, 3].repeated_combination(2).to_a # => [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]
combination
olası tekil sonucu, repeated_combination
pas edilen sayıya
göre tekrar da edebilen sonucu döner. Aynısı repeated_permutation
için de
geçerlidir:
[1, 2, 3].permutation(1).to_a # => [[1], [2], [3]]
[1, 2, 3].repeated_permutation(1).to_a # => [[1], [2], [3]]
[1, 2, 3].permutation(2).to_a # => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
[1, 2, 3].repeated_permutation(2).to_a # => [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
product
Array ve argüman olarak geçilecek diğer Array/lerin elemanlarıyla oluşabilecek tüm alternatifleri üretmenizi sağlar.
[1, 2, 3].product # => [[1], [2], [3]]
[1, 2, 3].product([4, 5]) # => [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]
[1, 2, 3].product([7, 8, 9]) # => [[1, 7], [1, 8], [1, 9], [2, 7], [2, 8], [2, 9], [3, 7], [3, 8], [3, 9]]
[1, 2, 3].product(["a", "b"], ["x", "y"]) # => [[1, "a", "x"], [1, "a", "y"], [1, "b", "x"], [1, "b", "y"], [2, "a", "x"], [2, "a", "y"], [2, "b", "x"], [2, "b", "y"], [3, "a", "x"], [3, "a", "y"], [3, "b", "x"], [3, "b", "y"]]
count
Az önce method olarak işlediğimiz count
ile başka ilginç işler de yapabiliyoruz:
a = [1, 2, 3, 4, 2]
a.count # => 5 # eleman sayısı
a.count(2) # => 2 # kaç tane 2 var?
a.count { |n| n % 2 == 0 } # => 3 # kaç tane 2’ye tam bölünen var?
cycle(n=nil) { |obje| blok } → nil
Pas edilen blok’u n defa tekrar eder.
a = [1, 2, 3]
a.cycle(2).to_a # => [1, 2, 3, 1, 2, 3] # 2 defa
a.cycle(4).to_a # => [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] # 3defa
a.cycle(2) { |o| puts "Sayı #{o}" }
# Sayı 1
# Sayı 2
# Sayı 3
# Sayı 1
# Sayı 2
# Sayı 3
Eğer [1, 2, 3].cycle { |i| puts i }
gibi bir işlem yaparsanız, default
olarak nil
geçmiş olursun ve bu sonsuz döngüle girer, sonsuza kadar 1, 2, 3,
1, 2, 3 .... şeklinde devam eder!
drop_while { |array| blok } → yeni array
delete_if
ile aynı işi yapar.
notlar = [40, 45, 53, 70, 99, 65]
notlar.drop_while {|notu| notu < 50 } # => [53, 70, 99, 65]
Koşula göre Array’den atar gibi düşünebilirsiniz. Not 50’den küçükse bırak.
take_while
Aynı drop_while
gibi çalışır ama tersini yapar:
notlar = [40, 45, 53, 70, 99, 65]
notlar.take_while { |notu| notu < 50 } # => [40, 45]
Koşula göre Array’e ekler gibi düşünebilirsiniz. Not 50’den küçükse sepete ekle! :)
each, each_index, each_with_index, each_slice, each_cons, each_with_object, reverse_each
Array ve hatta Enumator’lerin can damarıdır. Ruby yazarken siz de göreceksiniz
each
en sık kullandığınız iterasyon (yineleme / tekrarlama) yöntemi olacak.
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.each # => #<Enumerator: ["Uğur", "Yeşim", "Ezel", "Ömer"]:each>
a.each { |isim| puts "İsim: #{isim}" }
# İsim: Uğur
# İsim: Yeşim
# İsim: Ezel
# İsim: Ömer
Array ve içinde dolaşılabilir her nesnede işe yarar. Birde bunun index’li hali var;
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.each_index # => #<Enumerator: ["Uğur", "Yeşim", "Ezel", "Ömer"]:each_index>
a.each_index.to_a # => [0, 1, 2, 3]
a.each_index { |i| puts "Index: #{i}, Değeri: #{a[i]}" }
# Index: 0, Değeri: Uğur
# Index: 1, Değeri: Yeşim
# Index: 2, Değeri: Ezel
# Index: 3, Değeri: Ömer
ya da bu işi;
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.each_with_index { |eleman, index| puts "index: #{index}, eleman: #{eleman}" }
# index: 0, eleman: Uğur
# index: 1, eleman: Yeşim
# index: 2, eleman: Ezel
# index: 3, eleman: Ömer
each_slice
da Array’i gruplamak, parçalara ayırmak içindir. Geçilen
parametre bu işe yarar:
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.each_slice(2) # => #<Enumerator: ["Uğur", "Yeşim", "Ezel", "Ömer"]:each_slice(2)>
a.each_slice(2).to_a # => [["Uğur", "Yeşim"], ["Ezel", "Ömer"]]
a.each_slice(2) { |ikili_grup| puts "#{ikili_grup}" }
# ["Uğur", "Yeşim"]
# ["Ezel", "Ömer"]
each_cons
ise slice gibi ama mutlaka belirtilen miktarda parça üretir.
# 3’lü üret
[1, 2, 3, 4, 5,6].each_cons(3).to_a # => [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
# 4’lü üret
[1, 2, 3, 4, 5,6].each_cons(4).to_a # => [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
each_with_object
de ise, iterasyona girerken bir nesne pas edip, o nesneyi
doldurabilirsiniz.
[1, 2, 3, 4].each_with_object([]) { |number, given_object|
given_object << number * 2
} # => [2, 4, 6, 8]
number
Array’den gelen eleman (1, 2, 3, 4 gibi), given_object
ise
each_with_object([])
method’da geçtiğimiz boş Array []
.
reverse_each
aslında Array’i otomatik olarak ters çevirir yani reverse
eder ve içinde dolaşmanızı sağlar:
computers = ["Commodore 64", "Amiga", "Sinclair", "Amstrad"]
computers.reverse_each # => #<Enumerator: ["Commodore 64", "Amiga", "Sinclair", "Amstrad"]:reverse_each>
computers.reverse_each.to_a # => ["Amstrad", "Sinclair", "Amiga", "Commodore 64"]
computers.reverse_each { |c| puts "Bilgisayar: #{c}" }
# Bilgisayar: Amstrad
# Bilgisayar: Sinclair
# Bilgisayar: Amiga
# Bilgisayar: Commodore 64
find_index
İndeks’i ararken blok işleyebiliriz:
computers = ["Commodore 64", "Amiga", "Sinclair", "Amstrad"]
computers.find_index { |c| c == "Amstrad" } # => 3
freeze ve frozen?
Array’i kitlemek için kullanılır. Yani freeze (dondurulmuş) bir Array’e
yeni eleman eklenemez. Keza Array#sort
esnasında da otomatik olarak
freeze olur sort bitince buz çözülür!
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.freeze
a << "Fazilet" # Yeni isim eklemek mümkün değildir!
RuntimeError: can’t modify frozen Array
Array’de buzlanma var mı yok mu anlamak için frozen? kullanırız:
a = ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.freeze # => ["Uğur", "Yeşim", "Ezel", "Ömer"]
a.frozen? # => true
min, max, minmax, min_by, max_by ve minmax_by
min
ve max
ile Array elemanlarından en küçük/büyük değeri alırız:
a = [6, 1, 8, 4, 11]
a.min # => 1
a.max # => 11
Peki sayı yerine metinler olsa ne olacaktı?
m = ["a", "ab", "abc", "abcd"]
m.min # => "a"
m.max # => "abcd"
peki, m
Array’i şöyle olsaydı:
m = ["a", "ab", "abc", "abcd", "111111111"]
sonuç ne olurdu?
m = ["a", "ab", "abc", "abcd", "111111111"]
m.min # => "111111111" # ?
m.max # => "abcd"
Önce Comparable mı diyer bakılır, sayılar için çalışan bu yöntem,
String de a <=> b
karşılaştırmasına girer ve Lexicological
karşılaştırma yapar. "111111111"
karakter sayısı olarak diğerlerine göre çok
olmasına rağmen, min
değer olarak gelir. Eğer karakter sayına göre
karşılaştırma yapmak gerekiyorsa;
m = ["a", "ab", "abc", "abcd", "111111111"]
m.min { |a, b| a.length <=> b.length } # => "a"
m.max # => "abcd"
Şeklinde yapmak gerekir. Blok kullanabildiğimiz için aynı iş max
için de
geçerlidir. Ya da bu işleri yapabilmek için min_by
ve max_by
kullanabiliriz:
m = ["a", "ab", "abc", "abcd", "111111111"]
m.min_by { |x| x.length } # => "a"
m.max_by { |x| x.length } # => "111111111"
minmax
da Array’in minimum ve maximum’unu döner:
m = ["a", "ab", "abc", "abcd"]
m.min # => "a"
m.max # => "abcd"
m.minmax # => ["a", "abcd"]
Aynı mantıkta minmax_by
da gerekli şarta göre min, max döner:
m = ["a", "ab", "abc", "abcd"]
m.minmax_by { |x| x.length } # => ["a", "abcd"]
all?, any?, one?, none?
Array içindeki elemanları belli bir koşula göre kontrol etmek için kullanılır.
Sonuç Boolean yani true
ya da false
döner. Tüm elemanların kontrolü
koşula uyuyorsa true
uymuyorsa false
döner.
# acaba hayvanlar dizisindeki isimlerin hepsinin uzunluğu
# en az 2 karakter mi?
hayvanlar = ["Kedi", "Köpek", "Kuş", "Kurbağa", "Kaplumbağa"]
hayvanlar.all? { |hayvan_ismi| hayvan_ismi.length >= 2 } # => true
# Acaba ilk karfleri K harfimi?
hayvanlar.all? { |hayvan_ismi| hayvan_ismi.start_with?("K") } # => true
# Elemanların her biri true mu?
[true, false, nil].all? # => false
any?
de yanlızca bir tanesi true
olsa yeterlidir:
# En azından bir hayvan ismi A ile başlıyor mu?
hayvanlar = ["Kedi", "Köpek", "At", "Yılan", "Balık"]
hayvanlar.any?{ |hayvan_ismi| hayvan_ismi.start_with?("A") } # => true
one?
da ise sadece bir eleman koşula uymalıdır. Yani bir tanesi
true
dönmelidir. Eğer birden fazla eleman koşula true
dönerse sonuç false
olur:
hayvanlar = ["Kedi", "Köpek", "At", "Yılan", "Balık", "Kaplumbağa"]
# Sadece bir ismin uzunluğu 6 karaterten büyük olmalı!
hayvanlar.one?{ |hayvan_ismi| hayvan_ismi.length > 6 } # => true
# Uzunluğu 3’ten büyük 5 isim olduğu için false döndü!
hayvanlar.one?{ |hayvan_ismi| hayvan_ismi.length > 3 } # => false
none?
da ise hepsi false
olmalıdır ki sonuç true
dönsün:
hayvanlar = ["Kedi", "Köpek", "At", "Yılan", "Balık", "Kaplumbağa"]
# Hiçbir ismin uzunluğu 2 karakter olmamalı ? false. At’ın uzunluğu 2
hayvanlar.none?{ |hayvan_ismi| hayvan_ismi.length == 2 } # => false
# C ile başlayan hayvan ismi olmasın! true. Hiçbir isim C ile başlamıyor
hayvanlar.none?{ |hayvan_ismi| hayvan_ismi.start_with?("C") } # => true
inject, reduce*
inject
ve reduce
aynı işi yaparlar ve bir tür akümülator işlemi yapmaya
yararlar. Blok içinde 2 paramtre kullanılır. Başlama parametresi de alabilir.
Örneğin Array [1, 2, 3, 4, 5]
ve tüm elemanları birbiriyle toplamak
isitiyoruz.
[1, 2, 3, 4, 5].inject{ |toplam, eleman| toplam + eleman } # => 15
# işlem şu şekilde ilerliyor
# toplam: 0, eleman: 1
# toplam: 1, eleman: 2
# toplam: 3, eleman: 3
# toplam: 6, eleman: 4
# toplam: 10, eleman: 5
# sona geldiğinde toplam 10, eleman 5 -> 10 + 5 = 15
Eğer başlangıç değeri için parametre geçseydik, örneğin 10:
[1, 2, 3, 4, 5].inject(10){ |toplam, eleman| toplam + eleman } # => 25
# toplam: 10, eleman: 1
# toplam: 11, eleman: 2
# toplam: 13, eleman: 3
# toplam: 16, eleman: 4
# toplam: 20, eleman: 5
# sona geldiğinde toplam 20, eleman 5 -> 20 + 5 = 25
Aynı işi reduce
ile de yapabilirdik.
[1, 2, 3, 4, 5].reduce(:+) # => 15
Örnekte her elemanın +
methodu’nu çağırıyoruz ve sanki x = x + 1
mantığında, kendisini ekleye ekleye sonuca varıyoruz.
en_uzun_hayvan_ismi = ["kedi", "köpek", "kamplumbağa"].inject do |buffer, hayvan|
buffer.length > hayvan.length ? buffer : hayvan
end
en_uzun_hayvan_ismi # => "kamplumbağa"
partition ve group_by
partition
Array’i 2 parçaya ayırmaya yarar. Sonuç, blok’ta işlenen ifadeye
bağlı olarak [true_array, false_array]
olarak döner. Yani koşula true
cevap verenlerle false
cevap verenler ayrı parçalar halinde döner :)
[1, 2, 3, 4, 5, 6].partition{ |n| n.even? } # => [[2, 4, 6], [1, 3, 5]]
# Çift sayılar, true_array yani ilk parça: [2, 4, 6]
# Tek sayılar, false_array yani ikinci parça: [1, 3, 5]
# Sadece çift sayılar gelsin:
[1, 2, 3, 4, 5, 6].partition{ |n| n.even? }[0] # => [2, 4, 6]
group_by
gruplama yapmak için kullanılır. Sonuç Hash döner, ilk değer
(key) blok içindeki ifadenin sonucu, ikinci değer (value) ise sonucu
verenlerin oluşturdu gruptur. 1’den 6’ya kadar sayıları 3’e bölünce kaç
kaldığını gruplayarak bulalım:
[1, 2, 3, 4, 5, 6].group_by{ |n| n % 3 } # => {1=>[1, 4], 2=>[2, 5], 0=>[3, 6]}
# 3’e bölünce kalanı;
# 1 olanlar: [1, 4]
# 2 olanlar: [2, 5]
# 0 olanlar (tam bölünenler) : [3, 6]
Notu 50’den büyük olanlar:
notlar = [50, 20, 44, 60, 80, 100, 99, 81, 5]
notlar.group_by{ |notu| notu > 40 }[true] # => [50, 44, 60, 80, 100, 99, 81]
chunk
Array elemanları koşula göre gruplar.
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n| n.even? }.to_a
# => [
# [false, [3, 1]],
# [true, [4]],
# [false, [1, 5, 9]],
# [true, [2, 6]],
# [false, [5, 3, 5]]
# ]
slice_before
Array içinde belli bir elemana ya da kurala göre parçalara ayırmak için kullanılır.
[1, 2, 3, ’a’ , 4, 5, 6, ’a’ , 7 , 8 , 9 , ’a’ , 1 , 3 , 5].slice_before {|i| i == ’a’}.to_a
# => [[1, 2, 3], ["a", 4, 5, 6], ["a", 7, 8, 9], ["a", 1, 3, 5]]
flat_map, collect_concat
İkisi de aynı işi yapar.
Önce map
eder sonra flatten
yapar.
pos_neg = [1, 2, 3, 4, 5, 6].map { |n| [n, -n] }
pos_neg # => [[1, -1], [2, -2], [3, -3], [4, -4], [5, -5], [6, -6]]
pos_neg.flatten # => [1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6]
# yerine:
[1, 2, 3, 4, 5, 6].flat_map { |n| [n, -n] } # => [1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6]
sort_by
Aynı sort
gibi çalışır, Blok kullanır. İfadenin true
olmasına göre çalışır:
hayvanlar = ["kamplumbağa", "at", "eşşek", "kurbağa", "ayı"]
# isimleri uzunluklarına göre küçükten büyüğe doğru sıralayalım
hayvanlar.sort_by{ |isim| isim.length } # => ["at", "ayı", "eşşek", "kurbağa", "kamplumbağa"]
# isimleri uzunluklarına göre büyükten küçüğe doğru sıralayalım
hayvanlar.sort_by{ |isim| -isim.length } # => ["at", "ayı", "eşşek", "kurbağa", "kamplumbağa"]
bsearch
Binary arama yapar, O(log n)
formülünü uygular, buradaki n
Array’in
boyudur. Find minimum gibidir, yani koşula ilk uyanı bul gibi...
# 2’den büyük 3, 4 ve 5 olmasına rağmen tek sonuç
[1, 2, 3, 4, 5].bsearch{ |n| n > 2 } # => 3
[1, 2, 3, 4, 5].bsearch{ |n| n >= 4 } # => 4
Tehlikeli İşlemler
Başlarda da bahsettiğimiz gibi method ismi !
ile bitiyorsa bu ilgili nesnede
değişiklik yapıyor olduğumuz anlamına gelir. Array’lerde de bu tür method’lar
var:
[:reverse!, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :reject!, :slice!, :uniq!, :compact!, :flatten!, :shuffle!]
Bu method’lar orijinal Array’i bozar. Yani;
a = [1, 2, 3, 4, 5]
a.reverse! # => [5, 4, 3, 2, 1]
# a artık reverse edilmiş halde!
a # => [5, 4, 3, 2, 1]