14 hash (Sözlük, dictionary, birleşik array, map) 14.1 Hash Sınıfı Array ambarı, içindekileri tamsayılarla (index) damgalayıp sıralayan harika bir yapıdır. Ama bazı durumlarda indis ya yoktur ya da kullanılması kolay olmaz. Örneğin, bir sınıfta her öğrenciyi numarası ile belirlemek mümkündür, ama pratik değildir. Onun yerine soyadlarını adlarına eşleyen bir liste daha kullanışlı olur. hash, { } parantezi içine konulan anahtar => değer ikililerinden oluşan yapısal bir tiptir; bir sınıftır. Bazı dillerde sözlük, associative memories, associative arrays, map ya da hash tables adlarıyla bilinir. Adından da anlaşılacağı üzere, hash yapısı bir sözlük yapısı gibidir. Sözlükteki terimler anahtar, açıklamaları ise değer rolünü oynar. Ancak sözlüklerde terimler (anahtarlar) alfabetik (lexicographic) sıralıdır. hash yapısında anahtarlar sıralı olmayabilir. Anahtarlar ve değerler Ruby nesneleridir. Sözlüklerde olduğu gibi, anahtarlar tekrarlamayan tiplerden olmalıdır. Değerler her tipten olabilir. Tekrarlayabilirler. Başka bir deyişle, farklı anahtarlara aynı değer eşleşebilir (bkz. [10]). Bu kitapta, hash terimi yerine, çoğunlukla sözlük terimini kullanacağız. Ancak, bir dilin anahtar sözcüklerini değiştirmenin mümkün ya da uygun olmadığı deyimler vardır. O durumlarda, Ruby’nin kullandığı hash terimini kullanacağız. 174 BÖLÜM 14. HASH Arkadaşlarınızın, dostlarınızın adları karşısında telefon numaralarını yazdığınız basit bir liste, Ruby’de bir sözlük yapısıdır. Ruby’de hash ambarına konulan öğe çiftleri { } parantezi içine konulur. Anahtarın değere eşlendiği => simgesiyle gösterilir: anahtar=>değer. Örnek 14.1. t e l e f o n = { " Aren "=> ’ 0597 123 1234 ’ , " Meltem "=> ’ 01321 654 6789 ’ } Bu yapının öğeleri anahtar=>değer çiftlerinden oluşur. Öğe sayısı istediğiniz kadar artırılabilir. Ülke adlarının karşısında telefon kodları yazılı basit bir liste, Ruby’de bir sözlük yapısıdır. Örnek 14.2. u l u s l a r _ t l f = { ’ABD ’ => 1 , ’ Almanya ’ => 49 , ’ Fransa ’ => 33 , ’ T ü r k iye ’=> 90} Bu ambarda yalnızca dört tane anahtar => değer çifti vardır. Ama listeyi bütün ülkeleri içerecek kadar uzatabilirsiniz. İl adları karşısına trafik kodları yazılı basit bir liste, Ruby’de bir sözlük yapısıdır. Örnek 14.3. t r a f i k = { ’ B i t l i s ’ => " 13 " , ’ Van ’ => " 65 " , ’ D e n i z l i ’ => " 20 " , ’ Konya ’ => " 42 " , ’ Adana ’ => " 01 " } Bu ambarda yalnızca beş tane anahtar => değer çifti vardır. Ama listeyi bütün illeri içerecek kadar uzatabilirsiniz. Unutmayınız, hash yapısında anahtarlar tekrarlamaz, ama birden çok anahtara tek bir değer karşılık gelebilir. Örneğin, bir kurumda çalışanların ofis numaralarını gösteren bir sözlük yapısında, aynı ofisi paylaşanlar için ofis numaraları aynı olacaktır. Bir kurumda çalışanların ofislerini gösteren aşağıdaki memur => ofis biçimindeki listede Melis ile Yusuf 23 numaralı ofiste oturmaktadırlar. Listede, onlar için anahtarlar farklıdır, ama eğerler aynıdır. Örnek 14.4. y e r l e ş i m = { ’ M e l i s ’ => 2 3 , ’ Yusuf ’ => 2 3 , ’ Altan ’ => 25 } ; Bu sözlük’te ilk iki öğenin anahtarları farklı, ama değerleri aynıdır. 14.2. SÖZLÜK YAPISI ÜZERINDE İŞLEMLER 14.2 175 Sözlük Yapısı Üzerinde İşlemler Sözlük yapısı bir veri ambarıdır. Buna sözlük ambarı ya da kısaca ambar diyelim. Bu ambar üzerinde yapılacak başlıca işlemler şunlardır. • Ambara sözlük öğesi; yani anahtar:değer çifti koyma • Ambarda olan öğeleri görme • Ambarda bir anahtarın olup olmadığını anlama • Ambardaki öğeleri anahtar sırasına koyma • Ambardan sözlük öğesi çıkarıp kullanma • Ambardan sözlük öğesi atma (silme) 14.3 Sözlük Yaratma Bir sözlük yaratmanın farklı yöntemleri vardır. Başlıcalarını örneklerle açıklayalım. Boş sözlük Yaratma: { } parantezi boş bir sözlük yaratır. Örnek 14.5. d = {} d . length # => 0 Hash sınıfından Türetme: new operatörü Hash sınıfından boş bir sözlük yaratır. Örnek 14.6. d = Hash . new d . l e n g t h # => 0 anahtar => değer Çiftlerini Yazmak: { } parantezi içine sözlük yapısında yer alacak anahtar:değer çiftleri yazılabilir. Örneğin, bir işyerinde müdür, şef ve sekreterin ofis numaralarını gösteren Örnek 14.7. 176 BÖLÜM 14. HASH o f i s = { " müdür " => 310 , " ş e f " => 311 , " s e k r e t e r 1 " => 312 , " s e k r e t e r 2 " => 312} listesi bir sözlük yapısıdır. Bu yapıda anahtarlar tektir. Ama sekreter1 ve sekterer2 için ortak bir ofis ayrılmıştır. Bu demektir ki, sözlük yapısında anahtarlar tek olur, tekrarlamazlar, ama değerler tek olmayabilir. 14.3.1 Array ile Hash Yapılarının Karşılaştırılması Sözlük yapısı, array yapısı gibidir. Array yapısında her öğenin bir tamsayı indisi vardır. array’in öğelerine indisleriyle erişilir. Array’in öğeleri indislerine göre sıralıdır. Sözlük yapısında ise öğelerin indisleri yoktur. Onun yerine anahtarlar vardır. Anahtarlar indis rolünü oynarlar. Sözlük içindeki her öğe bir anahtar => değer çiftidir. Sözlükte öğe çiftlerine anahtar ile erişilir. Ama sözlük yapısı anahtarlara göre sıralı olmayabilir. Sözlük Yaratma neğin, Sözlük, Hash sınıfından ::new metodu ile yaratılır. Ör- puan = Hash . new deyimi puan adlı bir sözlük ambarı yaratır. 14.4 Hash Ambarına Öğe Koyma puan [ " Altan " ] = 75 deyimi puan adlı hash ambarına "Altan" => 75 çiftini bir öğe olarak koyar. Burada "Altan" anahtar, 75 ona karşılık getirilen değerdir. Bir hash ambarına istenildiği kadar öğe konulabilir. Ama anahtar tekrar edemez. Var olan bir anahtar tekrar kullanılırsa, ona önceden verilen değer silinir, yeni değeri eskisinin yerine geçer. Sözlük ambarı yaratılırken içine öğeler koymak mümkündür: k e n t = { ’ Ankara ’ => 3 1 2 , ’ İ s t a n b u l ’ => 2 1 2 , ’ İ z m i r ’ => 232} deyimi kent adlı bir sözlük ambarı yaratır ve içine üç kentin adlarını telefon kodlarına eşleyen üç öğe koyar. Daha sonra bu ambara yeni ekler yapılabilir: k e n t [ ’ Antalya ’ ] = 242 Anahtardan sonra gelen ok (=>) simgesi, anahtarı değere eşler. O nedenle, bazı kaynaklarda hash yapısına eşlem (map) denilir. 14.5. SÖZLÜK YAPISININ METOTLARI 177 Hash ambarında olmayan bir öğeye erişilmek istenildiğinde nil öntanımlı değeri gelir. Ama istersek bunu değiştirip, istediğimiz bir nesneyi öntanımlı yapabiliriz. Örneğin, h a f t a = Hash . new ( " İ y i g ü n l e r " ) deyimi hafta adlı hash ambarı için "İyi günler" nesnesini öntanımlı yapar. Öğesi olmayan sözlük ambarına erişim istendiğinde nil yerine, tanımlanan bu değer gelir. O nedenle, tanımlanan bu değere sözlük ambarının öntanımlı değeri diyeceğiz. Başka öntanımlı değer tanımlanmamışsa, boş sözlük ambarına erişim istendiğinde nil gelir. nil sözlük ambarının boş olduğu anlamına gelir. Örneğin, h = Hash . new h . d e f a u l t # => n i l olur. Ama, new operatöründe argüman kullanılırsa, aşağıdaki gibi olur: h = Hash . new ( 0 ) h . d e f a u l t # => 0 Ruby sözlük yapısında anahtar => değer çiftlerini oluşturan anahtarlar ve değerler her tipten olabilirler. Onlar birer nesnedir. Tek koşul, ambarda anahtar’ın tekrarlamamasıdır. Aynı nesne iki kez anahtar olarak kullanılamaz. Oysa, değer nesnesi birden çok kez yer alabilir. 14.5 Sözlük Yapısının Metotları Hash sınıfının çok sayıda metodu vardır. Onların listesini görmek için, Ruby’nin genel kuralını uygulayabiliriz. Bilindiği gibi, nesne.methods deyimi, sökonusu nesneye uygulanabilen bütün metotları listeler. Hash sınıfına uygulanabilen bütün metotları görmek için Hash . methods deyimi yeterlidir. Bu deyim uzun bir liste verir. Burada Hash sınıfının çok kullanılan bazı metotlarını örneklerle açıklayacağız. Örnek 14.8. d = { " Ankara " => 2 1 3 , " i z m i r " => ’ liman ’ , " Elma " => f a l s e } e = { ’ ab ’=> 1 2 , ’ cd ’ => " k e n t " , ’ e f ’ => t r u e } deyimleri d ve e adlarında iki sözlük ambarı yaratır ve { } içine, istenen öğeleri koyar. Uyarı 14.1. Nesne tabanlı programlama dillerinin çoğunda, her sınıfın metotları vardır. Bir sınıftan başka bir sınıftaki metot çağrılabilir. Ancak, 178 BÖLÜM 14. HASH Ruby’de durum farklıdır. Ruby’de metotlar modüllerde toplanır. Kernel adlı modülde toplanan metotlar, hemen her sınıfa uygulanabilir. Kernel Module’den üretilmiştir. Kernel’in metotları Ruby nesnelerinin orta malı gibidir. Şimdi amradaki öğelerin bileşenlerine nasıl erişileceğini görelim: 14.5.1 Anahtarlara Erişim keys metodu sözlükteki anahtarlara erişir: Örnek 14.9. d . keys # => [ " Ankara " , " i z m i r " , " Elma " ] p ( d . k e y s ) # =>["Ankara " , " i z m i r " , " Elma " ] Burada p() metodu print() metodunun kısa adıdır. Parametresini (argument) yazar. 14.5.2 Değerlere Erişim values metodu sözlükteki değerlere erişir: Örnek 14.10. d . values # => [ 2 1 3 , " liman " , f a l s e ] p ( d . v a l u e s ) # => [ 2 1 3 , " liman " , f a l s e ] 14.5.3 Kümesel İşlemler Sözlük ambarının anahtarları ve değerleri birer array olarak elde edilebildiğine göre, arrayler üzerinde yapılan kümesel arakesit (&), bileşim (+) ve fark (-) işlemleri uygulanabilir. Örnek 14.11. 3 d . keys & e . keys d . keys + e . keys d . keys − e . keys Bu kodları etkileşimli (irb) kipinde tek tek yazmak yerine hepsini bir program haline de getirebiliriz: Örnek 14.12. 14.5. SÖZLÜK YAPISININ METOTLARI 179 # e n c o d i n g u t f −8 2 d = { " ankara " => ’ k e n t ’ , " i z m i r " => ’ liman ’ , " k a r s " => ’ hudut ’ } e = { ’ ab ’=> 1 2 , " cd " => ’ liman ’ , ’ i z m i r ’ => 232 } 7 12 d . keys p(d . keys ) # => [ " ankara " , " i z m i r " , " k a r s " ] d . values p(d . values ) # => [ " k e n t " , " liman " , " hudut " ] e . keys p( e . keys ) # => [ " ab " , " cd " , " i z m i r " ] e . values p( e . values ) # => [ 1 2 , " liman " , 2 3 2 ] 17 22 4 9 d . keys & e . keys p(d . keys & e . keys ) # => a n a h t a r l a r i ç i n m a n t ı k s a l AND # => [ " i z m i r " ] d . keys + e . keys p(d . keys + e . keys ) izmir " ] # => a n a h t a r l a r ı n kümesel b i l e ş i m i # => [ " ankara " , " i z m i r " , " k a r s " , " ab " , " cd " , " d . keys − e . keys p(d . keys − e . keys ) # => a n a h t a r l a r ı n kümesel f a r k ı # => [ " ankara " , " k a r s " ] /∗ ∗ ruby hash01 . rb [ " ankara " , " i z m i r " , " k a r s " ] [ " k e n t " , " liman " , " hudut " ] [ " ab " , " cd " , " i z m i r " ] [ 1 2 , " liman " , 2 3 2 ] [ " izmir " ] [ " ankara " , " i z m i r " , " k a r s " , " ab " , " cd " , " i z m i r " ] [ " ankara " , " k a r s " ] ∗/ Her bir kodun karşısında verdiği sonuç yazılı olduğu için, başka açıklamaya gerek yoktur. d = { " ankara " => ’ k e n t ’ , " i z m i r " => ’ liman ’ , " k a r s " => ’ hudut ’ } hash ambarı verilmiş olsun. Aşağıdaki metotlar, karşılarında belirtilen eylemleri yaparlar d.methods : d nesnesine uygulanabilecek metotları listeler. d.length : d ambarındaki öğe sayısını verir. d . length # => 3 a.inspect : a ambarın içini gösterir. to_s gibidir. 180 BÖLÜM 14. HASH d. inspect => " { \ " ankara \"=>\" k e n t \ " , \ " i z m i r \"=>\" liman \ " , \ " k a r s \"=>\" hudut \ " } " to_s : inspect metodunun yaptığı işi yapar. d . to_s => " { \ " ankara \"=>\" k e n t \ " , \ " i z m i r \"=>\" liman \ " , \ " k a r s \"=>\" hudut \ " } " d.class: d nesnesinin hangi sınıftan türetildiğini belirtir. d. class # => Hash d.clear : d ambarındaki bütün öğeleri siler; boş ambar yapar. d. clear \{ \} d . length # => 0 d.keys : d ambarının anahtarlarını bir array biçiminde verir. d . keys # => [ " ankara " , " i z m i r " , " k a r s " ] d.values : d ambarının değerlerini bir array biçiminde verir. d . values # => [ " k e n t " , " liman " , " hudut " ] d.get(key) Argüman olarak yazılan değere eşleşen anahtarı verir. Eşleşen değer yoksa hiç (nil) verir. d . key ( ’ k e n t ’ ) # => " ankara " d . key ( 7 ) # => n i l hsh[key –> vlue] Verilen anahtara karşılık gelen değeri verir. 3 h = { " a " => 1 0 0 , " b " => 200 } h[ "a" ] #=> 100 h[ "c" ] #=> n i l == İki hash ambarının eşit olup olmadığını denetler. 2 7 h1 h2 h3 h4 h1 h2 h3 = { " a " => 1 , " c " => 2 } = { 7 => 3 5 , " c " => 2 , " a " => 1 } = { " a " => 1 , " c " => 2 , 7 => 35 } = { " a " => 1 , " d " => 2 , " f " => 35 } == h2 #=> f a l s e == h3 #=> t r u e == h4 #=> f a l s e hsh[key –> value] Verilen anahtara karşılık gelen değeri verir. 14.5. SÖZLÜK YAPISININ METOTLARI 3 181 h = { " a " => 1 0 0 , " b " => 200 } h[ "a" ] #=> 100 h[ "c" ] #=> n i l delete(anahtar) –> vlue Verilen anahtara karşılık gelen değeri verir. 2 h = { " a " => 1 0 0 , " b " => 200 } h. delete ( "a" ) h. delete ( "z" ) h . d e l e t e ( " z " ) { | e l | "#{ e l } not found " } #=> 100 #=> n i l #=> " z not found " delete_if{|key,value| block} : bloktakine eşleşen bütün anahtar-değer çiftlerini siler. 1 h = { " a " => 1 0 0 , " b " => 2 0 0 , " c " => 300 } h . d e l e t e _ i f { | key , v a l u e | key >= " b " } #=> { " a"=>100} each : bloktakine eşleşen bütün anahtar-değer çiftlerini verir. 3 h = { " a " => 1 0 0 , " b " => 200 } h . each { | key , v a l u e | p u t s "#{key } i s #{v a l u e } " } a i s 100 b i s 200 each_key{|anahtar| blok} : Bloktakine eşleşen bütün anahtarı verir. 1 h = { " a " => 1 0 0 , " b " => 200 } h . each_key { | key | p u t s key } a b each_value{|value| blok} : Bloktakine eşleşen bütün anahtarı verir. 1 h = { " a " => 1 0 0 , " b " => 200 } h . each_value { | v a l u e | p u t s v a l u e } 100 200 empty? : Ambar boş ise true verir. 1 { } . empty ? #=> t r u e fetch(anahtar) : Anahtara karşılık gelen değeri verir h = { " a " => 1 0 0 , " b " => 200 } h. fetch ( "a" ) h . f e t c h ( " z " , " go f i s h " ) #=> 100 #=> " go f i s h " has_key?(anahtar) : Verilen anahtar ambarda ise true verir. 2 h = { " a " => 1 0 0 , " b " => 200 } h . has_key ? ( " a " ) #=> t r u e h . has_key ? ( " z " ) #=> f a l s e 182 BÖLÜM 14. HASH include?(anahtar) : Verilen anahtar ambarda ise true verir. has_key metoduna denktir 2 h = { " a " => 1 0 0 , " b " => 200 } h . include ?( " a " ) #=> t r u e h . include ?( " z " ) #=> f a l s e has_value?(değer) : Verilen değer ambarda ise true verir. 2 h = { " a " => 1 0 0 , " b " => 200 } h . has_value ? ( 1 0 0 ) #=> t r u e h . has_value ? ( 9 9 9 ) #=> f a l s e invert : Bir bölükte anahtarları değer,değerleri anahtar yaparak yeni bir sözlük yaratır. 2 h = { " n " => 1 0 0 , "m" => 1 0 0 , " y " => 3 0 0 , " d " => 2 0 0 , " a " => 0 } h. invert #=> {0=>"a " , 100=>"m" , 200=>"d " , 300=>"y " } keys : Bir sölükte anahtarlardan oluşan bir array yaratır. h = { " a " => 1 0 0 , " b " => 2 0 0 , " c " => 3 0 0 , " d " => 400 } h . keys #=> [ " a " , " b " , " c " , " d " ]
© Copyright 2024 Paperzz