---
title: 'Diziler ve Karma Yapılar'
source: 'https://academia.sh/tr/kurslar/ruby-temelleri/diziler-ve-karma-yapilar'
course: 'Ruby Temelleri'
language: tr
updated: '2026-10-21T05:03:42+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Dizi ve karma yapının temel işlemlerini yazar ve sonuçlarını okur'
    - 'Bir koleksiyon yönteminin hangi sınıfta ya da modülde tanımlı olduğunu owner ile ölçer'
    - 'Varsayılan değer bloğunun eksik anahtarda nasıl yanıt verdiğini gösterir'
    - 'fetch ile köşeli parantez arasındaki farkı ve bloğun yalnız anahtar yokken koştuğunu ölçer'
---

# Diziler ve Karma Yapılar

Ruby'nin iki temel koleksiyonu olan dizi ve karma yapının hangi yöntemleri kendisinin, hangilerini ortak bir modülün yanıtladığı ve eksik bir anahtarın değerini bloğun belirlediği ölçülür.

Semboller ve Dizgiler dersi, `"ad".to_sym` iletisini `String` sınıfının yanıtladığını ve elde edilen `:ad` sembolünün, aynı değeri tek bir nesne olarak taşıdığı için `equal?` ile karşılaştırılabildiğini ölçtü. Sembolün asıl işi o derste henüz görünmedi: karma yapıda anahtar olmak. Bu ders iki temel koleksiyonu, diziyi ve karma yapıyı, ve aynı kursun sorusunu bu koleksiyonlara yöneltiyor: bir yönteme gelen **iletiyi kim yanıtlıyor**?

Kursun dört yanıtlayanı değişmez: **sınıf**, **modül**, **blok** ve **sözdizimi**. Düzyazıda ölçü kategorisi kastedildiğinde "yanıtlayan sınıf" yazılır; çıplak "sınıf" Ruby'nin `Class`'ıdır. Değişkenler, tipler ve döngüler M01/K02'de kavram olarak kuruldu; burada dizi **(array)**, sıralı ve sıfırdan numaralanan bir eleman listesidir. **Karma yapı (hash)** ise anahtardan değere giden bir eşlemedir ve elemanlarını eklenme sırasıyla tutar.

## Temel İşlemler

İlk ölçüm yalnız davranışı gösterir. Dizi köşeli parantezle yazılır, `<<` sona eleman ekler, negatif indis sondan sayar, aralık bir dilim verir. Karma yapı süslü parantez ve `anahtar: değer` biçimiyle yazılır; bu biçimde anahtarlar semboldür.

```ruby
# temel.rb — dizi ve karma yapinin temel islemleri
dizi = [10, 20, 30]
dizi << 40
puts "ilk=#{dizi[0]} son=#{dizi[-1]} adet=#{dizi.size} disarda=#{dizi[10].inspect}"
puts "dilim=#{dizi[1..2].inspect} ilk_iki=#{dizi.first(2).inspect}"

karma = { ad: "Ayse", yas: 30 }
karma[:sehir] = "Izmir"
puts "ad=#{karma[:ad]} yok=#{karma[:mail].inspect} anahtarlar=#{karma.keys.inspect}"
karma.each { |anahtar, deger| puts "#{anahtar} -> #{deger}" }
puts karma.select { |_, deger| deger.is_a?(String) }.inspect
puts karma.map { |anahtar, deger| anahtar }.inspect
```
```
ilk=10 son=40 adet=4 disarda=nil
dilim=[20, 30] ilk_iki=[10, 20]
ad=Ayse yok=nil anahtarlar=[:ad, :yas, :sehir]
ad -> Ayse
yas -> 30
sehir -> Izmir
{ad: "Ayse", sehir: "Izmir"}
[:ad, :yas, :sehir]
```

Dizi sınırının dışındaki indis hata vermez, `nil` döndürür; karma yapıda olmayan anahtar da öyle. Bu iki sessiz `nil` bu dersin ikinci yarısındaki sorunun zeminidir: eksik bir anahtarın sonucunu belirleyen şey nedir? Karma yapı eklenme sırasını korur; `anahtarlar` satırındaki sıra `sehir` atamasının sona eklendiğini gösteriyor. `select` ve `map` aynı iki parametreli blok biçimini aldı, ama biri karma yapı döndürdü, öteki dizi. Bunun nedeni sonraki bölümde ölçülen sahiplik ayrımıdır. **KB1.** Ölçümler sembol anahtarlı karma yapılarla yapıldı; dizgi anahtarlı karma yapılar bu derste ölçülmedi ve sonuçlar onlara taşınmaz.

## Yöntemi Hangi Tanım Taşıyor

Aynı koleksiyon üzerinde yazılan iki yöntem, aynı biçimde çağrılsa da farklı yerlerde tanımlı olabilir. `method(:ad).owner`, o yöntemi tanımlayan sınıfı ya da modülü verir. Bu ders arama sırasını göstermez; yalnız sonucu, yani sahibi okur.

```ruby
# koleksiyon.rb — koleksiyon yontemlerinin sahibi kim
dizi = [1, 2, 3]
karma = { a: 1, b: 2 }

puts "dizi.size     #{dizi.method(:size).owner}"
puts "dizi.map      #{dizi.method(:map).owner}"
puts "karma.each    #{karma.method(:each).owner}"
puts "karma.select  #{karma.method(:select).owner}"
puts "karma.fetch   #{karma.method(:fetch).owner}"
puts "karma.map     #{karma.method(:map).owner}"
```
```
dizi.size     Array
dizi.map      Array
karma.each    Hash
karma.select  Hash
karma.fetch   Hash
karma.map     Enumerable
```

Ruby 4.0.7'de beş yöntemi bir sınıf karşıladı: `size` ve `map` `Array`'de, `each`, `select` ve `fetch` `Hash`'te tanımlı. Altıncısı farklı: `karma.map` `Hash`'te değil, `Enumerable` modülünde tanımlı. Yani aynı `map` adı dizide sınıfın, karma yapıda modülün yanıtıdır. Hangi yöntemin hangi tanımda durduğu sürümden sürüme taşınabilir; bu yüzden sonuç dilin sözü değil bu sürümün ölçümü olarak okunur. `Enumerable` modülü üçüncü derstir ve burada yalnız adı anılır. Önceki bölümde `select` karma yapı, `map` dizi döndürdü: `select` `Hash`'in kendi yöntemi olduğu için sonucu da karma yapı olarak kurar, `Enumerable`'dan gelen `map` ise her zaman dizi üretir.

## Eksik Anahtarın Değerini Kim Veriyor

Temel işlemlerde `karma[:mail]` `nil` döndürdü. Bu davranışı değiştirmek için karma yapı kurulurken bir varsayılan değer verilebilir. İki biçimi vardır: `Hash.new(0)` sabit bir değer, `Hash.new { ... }` ise bir **blok** verir ve anahtar eksik kaldığında o blok koşar. Blok, anahtarı parametre olarak alabilir; böylece sonuç anahtara bağlı olabilir. M12/K02, PHP'de paylaşılan varsayılan bir değerin değişikliği nereye ulaştırdığını ölçmüştü; burada o soru sorulmuyor, yalnız varsayılan değeri kimin ürettiği ölçülüyor.

Kursun ortak yardımcısı `yanit.rb` önce birebir verilir. Bir ifadeyi sırayla üç soruyla sınıflandırır: `defined?` bir yöntem çağrısı mı diyor, iki farklı blok iki farklı sonuç veriyor mu, yöntemin sahibi bir `Class` mı. Çıktı bloğu olmadığı için yalnız diske yazılır.

```ruby
# yanit.rb — bir iletiyi kimin yanitladigini siniflandiran yardimcilar

# Siniflandirma sirayla sorar: once ifade bir ileti mi (defined?),
# sonra iki farkli blok iki farkli sonuc veriyor mu, sonra yontemin sahibi kim.
def yanitlayan(tanim, sahip: nil, sonuc: nil, bloklu: nil)
  return ["sozdizimi", "defined? #{tanim}"] unless tanim == "method"

  if bloklu
    birinci, ikinci = bloklu.call
    return ["blok", "#{birinci.inspect} / #{ikinci.inspect}"] unless birinci == ikinci
  end

  tur = sahip.instance_of?(Class) ? "sinif" : "modul"
  [tur, "#{sahip}, sonuc #{sonuc.inspect}"]
end
```

Şimdi çekirdeğin `varsayilan deger` gözlemi koşar. İki `Hash.new` bloğu aynı `[:x]` iletisine bakıyor: biri her zaman `0`, ötekisi anahtarın metin karşılığını döndürüyor. Ardından sabit varsayılanlı biçim ve `defined?`'in iki durumu basılır.

```ruby
# varsayilan.rb — eksik anahtarin degerini kim veriyor
require_relative "yanit"

sifir = Hash.new { 0 }
metin = Hash.new { |_, anahtar| anahtar.to_s }

tur, kanit = yanitlayan(defined?(Hash.new), bloklu: -> { [sifir[:x], metin[:x]] })
puts "#{tur}  #{kanit}"
puts Hash.new(0)[:x]
puts defined?(Hash.new)
puts defined?(Hash.new { 0 })
```
```
blok  0 / "x"
0
method
expression
```

Birinci satır, çekirdeğin `varsayilan deger` satırıdır: **blok** yanıtlayan. Aynı `[:x]` iletisi iki karma yapıda `0` ve `"x"` verdi; iletiyi alan nesnenin sınıfı aynıydı (`Hash`), fark yalnız verilen bloktaydı. Bu yüzden yanıtı sınıf ya da modül değil blok belirler. İkinci satırda sabit varsayılanlı `Hash.new(0)[:x]` da `0` verdi; orada bir blok yoktur, değer kurulurken verilmiştir.

Son iki satır kuralın bir inceliğini gösteriyor. `defined?(Hash.new)` `"method"` döndürür, ama bloklu çağrı olan `defined?(Hash.new { 0 })` `"expression"` döndürür. Çekirdek bu yüzden iletiyi **bloksuz** sorgular ve bloğun etkisini ikinci adımda ölçer; bloklu biçimi sorgulasaydı birinci adım iletiyi sözdizimi sayardı. **KB2.** Bloklu `defined?` sonucu Ruby 4.0.7'de ölçüldü; başka bir sürümde aynı sonuç varsayılmaz. Bu ayrıntı Bloklar dersinde adlandırılır.

## Dizi İşlemleri

Temel İşlemler bölümü yalnız `<<` ve tek indisli erişimi yazdı. Dizinin sık kullanılan öteki işlemleri sona ekleme, sondan çıkarma ve dilimlemedir. Sonsuz uçlu aralık `a[1..]` ilk elemandan sonrasını verir, `first(2)` baştan iki eleman alır. `push` ve `<<` sona ekler; `pop` son elemanı hem diziden çıkarır hem döndürür.

```ruby
# dizi_islem.rb — dilimleme, ekleme ve cikarma
a = [5, 3, 8, 1]
puts "a[1..]=#{a[1..].inspect} a[-1]=#{a[-1]} first(2)=#{a.first(2).inspect}"
a.push(9)
a << 7
puts "sonra=#{a.inspect}"
puts "pop=#{a.pop} kalan=#{a.inspect}"
```
```
a[1..]=[3, 8, 1] a[-1]=1 first(2)=[5, 3]
sonra=[5, 3, 8, 1, 9, 7]
pop=7 kalan=[5, 3, 8, 1, 9]
```

Dilimleme ve `first(2)` birer dizi döndürdü ve `a`'yı değiştirmedi: `push` satırına gelindiğinde `a` hâlâ özgün dört elemanı taşıyordu. `push(9)` ve `<<` aynı işi yaptı ve dizi altı elemana çıktı. `pop` `7` döndürdü ve dizi beş elemana indi: `pop`'un iki etkisi vardır, bir değer döndürmesi ve diziyi değiştirmesi. **KB19.** Dilimin yeni bir dizi mi yoksa aynı belleğin bir görünümü mü olduğuna bakılmadı; yalnız yazdırılan değerler ölçüldü.

## Yerinde Değiştiren Biçim

Birçok dizi yönteminin iki biçimi vardır: yeni bir dizi döndüren ve diziyi yerinde değiştiren. Sıralamada bu çift `sort` ve onun yerinde sıralayan biçimidir. Fark `equal?` ile ölçülür: iki değişken aynı nesneyi mi gösteriyor?

```ruby
# yerinde.rb — yeni dizi ile ayni dizinin degismesi
a = [3, 1, 2]
b = a.sort
puts "yeni=#{b.inspect} a=#{a.inspect} ayni_nesne=#{a.equal?(b)}"
c = a.sort!
puts "yerinde a=#{a.inspect} ayni_nesne=#{a.equal?(c)}"
puts "sahip=#{a.method(:sort!).owner}"
```
```
yeni=[1, 2, 3] a=[3, 1, 2] ayni_nesne=false
yerinde a=[1, 2, 3] ayni_nesne=true
sahip=Array
```

`sort` yeni bir dizi verdi: `b` sıralıydı, `a` özgün sırasında kaldı ve `equal?` `false` döndü. Yerinde sıralayan biçim `a`'nın kendisini sıraladı ve aynı nesneyi geri verdi: `a` `[1, 2, 3]` oldu, `equal?` `true`. Yerinde sıralayan biçimin sahibi `Array` olarak basıldı, yani yanıtlayan bir sınıftır; iki biçimin farkı yöntemin sonucunun yeni nesne mi yoksa alıcının kendisi mi olduğundadır. **KB20.** Ölçüm yalnız sıralama çiftine yapıldı; başka çiftlerin aynı kalıbı izlediği varsayılmaz.

## Karma Yapıda Sıra ve İç İçe Erişim

Karma yapı eklenme sırasını korur ve `to_a` onu çift dizisine çevirir. İç içe karma yapılarda `dig` anahtarları sırayla izler; yol bir yerde kesilirse hata fırlatmak yerine `nil` döndürür.

```ruby
# karma_ek.rb — ekleme sirasi, to_a ve dig
k = { b: 1, a: 2 }
k[:c] = 3
puts k.keys.inspect
puts k.to_a.inspect
ic = { kullanici: { adres: { sehir: "Izmir" } } }
puts ic.dig(:kullanici, :adres, :sehir)
puts ic.dig(:kullanici, :telefon, :no).inspect
```
```
[:b, :a, :c]
[[:b, 1], [:a, 2], [:c, 3]]
Izmir
nil
```

`k` önce `b` ve `a` anahtarlarıyla kuruldu, `c` sona eklendi; `keys` bu sırayı, `to_a` aynı sırayı çiftler hâlinde verdi. Alfabetik bir sıralama yoktur. `dig` üç anahtarı izleyip `Izmir`'i buldu; ikinci çağrıda `:telefon` yoktu ve `dig` hata fırlatmadan `nil` verdi. **KB21.** Sıra davranışı Ruby 4.0.7'de ve yalnız bu örnekle ölçüldü.

## Paylaşılan Varsayılan Nesne

Varsayılan değeri blok yerine bir nesne olarak vermek, `Hash.new([])` biçiminde, bir tuzak taşır: o nesne tektir ve her eksik anahtar için aynısı döner. M12/K02 paylaşılan varsayılan değerin davranışını başka bir dilde ölçmüştü; burada Ruby'deki çıktı yalnız okunur.

```ruby
# ortak.rb — paylasilan varsayilan nesne ile blok bicimi
ortak = Hash.new([])
ortak[:a] << 1
ortak[:b] << 2
puts "ortak=#{ortak.inspect} varsayilan=#{ortak.default.inspect} anahtarlar=#{ortak.keys.inspect}"
ayri = Hash.new { |h, k| h[k] = [] }
ayri[:a] << 1
ayri[:b] << 2
puts ayri.inspect
```
```
ortak={} varsayilan=[1, 2] anahtarlar=[]
{a: [1], b: [2]}
```

`ortak[:a] << 1` eksik anahtar için varsayılan diziyi aldı ve ona ekledi; karma yapıya bir anahtar atanmadı. Bu yüzden `ortak` boş kaldı, `anahtarlar` `[]` oldu ve varsayılan dizi `[1, 2]` oldu: `:a` ve `:b` aynı diziye yazdı. Blok biçimi ise her eksik anahtarda bloğu koşturup sonucu `h[k] = []` ile karma yapıya yazdı; iki anahtar iki ayrı dizi aldı. Eksik anahtarın değerini ilk biçimde tek bir nesne, ikinci biçimde her seferinde blok veriyor. **KB22.**

## Karma Yapıyı Dönüştürmek

Karma yapıdan yeni bir karma yapı ya da tek bir değer üretmek sık gerekir. `transform_values` değerleri dönüştürür, `to_h` bloğuyla anahtarları da değiştirebilir, `sum` ise `Enumerable` üzerinden gelir. Dizi tarafında `compact` `nil` elemanları atar, `uniq` yinelenenleri eler, `flatten` iç içe diziyi düzleştirir.

```ruby
# donustur.rb — karma yapi donusumleri ve dizi temizligi
k = { a: 1, b: 2 }
puts k.transform_values { |v| v * 10 }.inspect
puts k.to_h { |a, v| [a.to_s, v] }.inspect
puts k.sum { |_, v| v }
puts k.min_by { |_, v| -v }.inspect
puts "sahip=#{k.method(:transform_values).owner} #{k.method(:sum).owner} #{k.method(:to_h).owner}"
d = [3, 1, 2, 3, nil]
puts d.compact.uniq.sort.inspect
puts [[1, [2]], [3]].flatten.inspect
```
```
{a: 10, b: 20}
{"a" => 1, "b" => 2}
3
[:b, 2]
sahip=Hash Enumerable Hash
[1, 2, 3]
[1, 2, 3]
```

`transform_values` yalnız değerleri çarptı ve anahtarlar korundu; `to_h` bloğu her çifti `[anahtar, değer]` olarak döndürünce anahtarlar dizgiye çevrildi. `sum` değerleri toplayıp `3` verdi, `min_by` `-v` değeri en küçük olan çifti, yani `[:b, 2]`'yi seçti. Sahip satırı ayrımı gösterir: `transform_values` ve `to_h` `Hash`'te, `sum` ise `Enumerable`'dadır. `compact`, `uniq` ve `sort` zinciri `nil`'i ve yinelenen `3`'ü atıp `[1, 2, 3]` verdi; `flatten` iç içe diziyi `[1, 2, 3]` yaptı. **KB38.** Bu yöntemlerin başka alıcılarda aynı sahibi taşıdığı varsayılmaz.

## Sınırlayıcı Ölçüm

Blok her eksiklikte mi yanıtlıyor, yoksa yalnız belirli bir durumda mı? `fetch` yöntemi bunu açıkça ölçer. `fetch` anahtarı arar; bulursa değeri döndürür. Bulamazsa bir blok verilmişse bloğu koşturur, verilmemişse hata fırlatır. Aşağıdaki ölçüm bloğun kaç kez koştuğunu bir sayaçla sayar. Bu sayaç, kaç kez koştuğu sorusunun bir cevabı olarak okunmaz: M10/K03 o soruyu başka bir eksende ölçmüştü, burada sayaç yalnız bloğun hiç çağrılmadığını göstermek içindir.

```ruby
# fetch.rb — blok yalniz anahtar yoksa yanitliyor
cagri = 0
karma = { a: 1 }

var = karma.fetch(:a) { cagri += 1; 0 }
yok = karma.fetch(:b) { |anahtar| cagri += 1; anahtar.to_s }
puts "var=#{var.inspect} yok=#{yok.inspect} cagri=#{cagri}"

bloksuz = begin
  karma.fetch(:b)
rescue KeyError => hata
  hata.class
end
puts "bloksuz=#{bloksuz}"
puts "kose=#{karma[:b].inspect}"
puts "sahip=#{karma.method(:fetch).owner}"
```
```
var=1 yok="b" cagri=1
bloksuz=KeyError
kose=nil
sahip=Hash
```

`fetch` aynı eksik anahtar için üç farklı sonuç verdi. Bloklu çağrı `"b"` döndürdü, bloksuz çağrı `KeyError` fırlattı, köşeli parantez `nil` döndürdü. Anahtar var olduğunda ise sayaç artıran bloklu `fetch(:a)` `1` döndürdü ve sayaç yalnız bir kez arttı: o artış, anahtarı olmayan çağrıya aittir. Yani blok anahtar bulunduğunda hiç çağrılmadı. Bloğun yanıtladığı durum eksik anahtardır; var olan anahtarın değeri hiçbir blok sormadan karma yapının kendisinden gelir.

Bu, ilk bölümdeki yanıtlayanı daraltır. `fetch`'in sahibi `Hash` yani bir sınıf, ama sonucu eksik anahtarda blok belirliyor. Çekirdeğin sınıflandırması bu yüzden blokluyu ayrı bir adımda ölçer: iletinin sahibi her zaman bir sınıf ya da modüldür, soru sonucun kimden geldiğidir. `Hash.new { ... }` gibi `fetch` de varsayılanı çağıranın elinde bırakır; ikisinin farkı, `Hash.new` bloğunun karma yapıya kalıcı olarak bağlanması, `fetch` bloğunun ise yalnız o çağrıya ait olmasıdır.

## Özet

- Dizi sıralı ve sıfırdan numaralanan bir listedir; karma yapı anahtardan değere giden, eklenme sırasını koruyan bir eşlemedir. Sınır dışı indis ve eksik anahtar `nil` döndürür.
- Ruby 4.0.7'de `size`, `map` (dizide), `each`, `select` ve `fetch` kendi sınıflarında tanımlıdır; `karma.map` ise `Enumerable` modülündedir.
- Bu dersin yanıtlayanı **blok**tur: `Hash.new { 0 }[:x]` `0`, `Hash.new { |_, k| k.to_s }[:x]` `"x"` verdi; iletiyi alan sınıf aynıydı, fark verilen bloktaydı.
- `defined?` bloklu çağrıda `"expression"` döndürür; çekirdek iletiyi bloksuz sorgular.
- Sınırlayıcı ölçüm: blok yalnız anahtar yokken yanıtlar. Sayaç artıran bloklu `fetch(:a)` var olan anahtarda `1` döndürür ve blok hiç koşmaz.

## Sonraki Adım

Bu derste blok iki karma yapının sonucunu ayırdı, ama blokun kendisi henüz bir konu olarak ele alınmadı: `{ |_, k| k.to_s }` ve `{ 0 }` yalnız yazıldı. Bloklar dersi aynı `map` iletisini iki farklı blokla koşturur ve bir yöntemin, kendisine verilen bloğu nasıl çağırdığını ölçer.
