D Programlama Dili – Programlama dersleri ve D referansı
Ali Çehreli

aralık: [range], belirli biçimde erişilen bir grup eleman
atama: [assign], değişkene yeni bir değer vermek
dilim: [slice], başka bir dizinin bir bölümüne erişim sağlayan yapı
dinamik: [dynamic], çalışma zamanında değişebilen
dizi: [array], elemanları yan yana duran ve indeksle erişilen topluluk
ifade: [expression], programın değer oluşturan veya yan etki üreten bir bölümü
indeks: [index], topluluk elemanlarına erişmek için kullanılan bilgi
nitelik: [property, attribute], bir türün veya nesnenin bir özelliği
Phobos: [Phobos], D dilinin standart kütüphanesi
referans: [reference], asıl nesneye, onun takma ismi gibi erişim sağlayan program yapısı
sığa: [capacity], yeni elemanlar için önceden ayrılmış olan yer
topluluk: [container], aynı türden birden fazla veriyi bir araya getiren veri yapısı
... bütün sözlük



İngilizce Kaynaklar


Diğer




Başka Dizi Olanakları

Elemanları bir araya getirmeye yarayan dizileri Diziler bölümünde görmüştük. O bölümü kısa tutmak için özellikle sonraya bıraktığım başka dizi olanaklarını burada göstereceğim.

Ama önce karışıklığa neden olabileceğini düşündüğüm bazı terimleri listelemek istiyorum:

Bu bölümde özellikle dilim dediğim zaman dilimleri (yani dinamik dizileri), yalnızca dizi dediğim zaman da fark gözetmeden dilimleri ve sabit uzunluklu dizileri kasdetmiş olacağım.

Dilimler

Dilimler aslında dinamik dizilerle aynı olanaktır. Bu olanağa; dizi gibi kullanılabilme özelliği nedeniyle bazen dinamik dizi, başka dizinin bir parçasına erişim sağlama özelliği nedeniyle de bazen dilim denir. Var olan başka bir dizinin elemanlarının bir bölümünü sanki daha küçük farklı bir diziymiş gibi kullandırmaya yarar.

Dilimler, elemanları bir başlangıç indeksinden bir bitiş indeksine kadar belirlemeye yarayan aralık söz dizimiyle tanımlanırlar:

  aralığın_başı .. aralığın_sonundan_bir_sonrası

Başlangıç indeksi aralığa dahildir; bitiş indeksi aralığın dışındadır:

/* ... */ = ayGünleri[0 .. 3];  // 0, 1, ve 2 dahil; 3 hariç

Not: Burada anlatılan aralıklar Phobos kütüphanesinin aralık kavramından farklıdır. Sınıf ve yapı arayüzleriyle ilgili olan Phobos aralıklarını daha ilerideki bir bölümde göstereceğim.

Örnek olarak ayGünleri dizisini dörde dilimleyerek birbirinden farklı dört çeyrek diziymiş gibi şöyle kullanabiliriz:

    int[12] ayGünleri =
        [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

    int[] ilkÇeyrek    = ayGünleri[0 .. 3];
    int[] ikinciÇeyrek = ayGünleri[3 .. 6];
    int[] üçüncüÇeyrek = ayGünleri[6 .. 9];
    int[] sonÇeyrek    = ayGünleri[9 .. 12];

O kodda tanımlanan son dört değişken dilimdir; her birisi asıl dizinin dört değişik bölgesine erişim sağlamaktadır. Buradaki önemli nokta, o dilimlerin kendilerine ait elemanlarının bulunmadığıdır. Onlar asıl dizinin elemanlarına erişim sağlarlar. Bir dilimdeki bir elemanın değiştirilmesi asıl dizideki asıl elemanı etkiler. Bunu görmek için dört çeyreğin ilk elemanlarına dört farklı değer verelim ve asıl diziyi yazdıralım:

    ilkÇeyrek[0] =    1;
    ikinciÇeyrek[0] = 2;
    üçüncüÇeyrek[0] = 3;
    sonÇeyrek[0] =    4;

    writeln(ayGünleri);

Değişen elemanları işaretlenmiş olarak gösteriyorum:

[1, 28, 31, 2, 31, 30, 3, 31, 30, 4, 30, 31]

Dikkat ederseniz, her dilim kendisinin 0 numaralı elemanını değiştirdiğinde o dilimin asıl dizide erişim sağladığı ilk eleman değişmiştir.

Dizi indekslerinin 0'dan başladıklarını ve dizinin uzunluğundan bir eksiğine kadar olduklarını daha önce görmüştük. Örneğin 3 elemanlı bir dizinin yasal indeksleri 0, 1, ve 2'dir. Dilim söz diziminde bitiş indeksi aralığın sonundan bir sonrası anlamına gelir. Bu yüzden, dizinin son elemanını da aralığa dahil etmek gerektiğinde ikinci indeks olarak dizinin uzunluğu kullanılır. Örneğin uzunluğu 3 olan bir dizinin bütün elemanlarına erişim sağlamak için dizi[0..3] yazılır.

Aralık söz dizimindeki doğal bir kısıtlama, başlangıç indeksinin bitiş indeksinden büyük olamayacağıdır:

    int[3] dizi = [ 0, 1, 2 ];
    int[] dilim = dizi[2 .. 1];  // ← çalışma zamanı HATASI

Başlangıç indeksinin bitiş indeksine eşit olması ise yasaldır ve boş dilim anlamına gelir:

    int[] dilim = birDizi[indeks .. indeks];
    writeln("Dilimin uzunluğu: ", dilim.length);

indeks'in yasal bir indeks değeri olduğunu kabul edersek, çıktısı:

Dilimin uzunluğu: 0
dizi.length yerine $

Dizi elemanlarını [] işleci ile indekslerken bazen dizinin uzunluğundan da yararlanmak gerekebilir. Bu konuda kolaylık olarak ve yalnızca [] işleci içindeyken, dizi.length yazmak yerine kısaca $ karakteri kullanılabilir:

    writeln(dizi[dizi.length - 1]);   // dizinin son elemanı
    writeln(dizi[$ - 1]);             // aynı şey
Kopyasını almak için .dup

İsmi "kopyala" anlamına gelen "duplicate"in kısası olan .dup niteliği, var olan bir dizinin elemanlarının kopyasından oluşan yeni bir dizi üretir:

    double[] dizi = [ 1.25, 3.75 ];
    double[] kopyası = dizi.dup;

Bir örnek olarak Şubat'ın 29 gün çektiği senelerdeki ayların gün sayılarını tutan bir dizi oluşturmak isteyelim. Bir yöntem, önce normal senelerdeki ayGünleri'nin bir kopyasını almak ve o kopya dizideki Şubat'ın gün sayısını bir arttırmaktır:

import std.stdio;

void main() {
    int[12] ayGünleri =
        [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

    int[] artıkYıl = ayGünleri.dup;

    ++artıkYıl[1];   // yeni dizideki Şubat'ın gün sayısını
                     // arttırır

    writeln("Normal: ", ayGünleri);
    writeln("Artık : ", artıkYıl);
}

Çıktısı:

Normal: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Artık : [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Atama işlemi

Değerini değiştirme olarak bildiğimiz atama işlemi, sabit uzunluklu dizilerde de aynı anlamdadır; elemanların değerleri değişir:

    int[3] a = [ 1, 1, 1 ];
    int[3] b = [ 2, 2, 2 ];

    a = b;        // a'nın elemanları da 2 olur
    writeln(a);

Çıktısı:

[2, 2, 2]

Dilimlerle kullanıldığında ise atama işleminin anlamı çok farklıdır: Dilimin, erişim sağlamakta olduğu elemanları bırakmasına ve yeni elemanlara erişim sağlamaya başlamasına neden olur:

    int[] tekler = [ 1, 3, 5, 7, 9, 11 ];
    int[] çiftler = [ 2, 4, 6, 8, 10 ];

    int[] dilim;     // henüz hiçbir elemana erişim sağlamıyor

    dilim = tekler[2 .. $ - 2];
    writeln(dilim);

    dilim = çiftler[1 .. $ - 1];
    writeln(dilim);

Yukarıdaki koddaki dilim başlangıçta hiçbir dizinin elemanına erişim sağlamazken önce tekler'in bazı elemanlarına, sonra da çiftler'in bazı elemanlarına erişim sağlar:

[5, 7]
[4, 6, 8]
Uzunluğun artması paylaşımı sonlandırabilir

Sabit dizilere eleman eklenemediği için bu konu yalnızca dilimlerle ilgilidir.

Aynı elemana aynı anda birden fazla dilimle erişilebilir. Örneğin aşağıdaki sekiz elemanın ilk ikisi üç dilim tarafından paylaşılmaktadır:

import std.stdio;

void main() {
    int[] dilim = [ 1, 3, 5, 7, 9, 11, 13, 15 ];
    int[] yarısı = dilim[0 .. $ / 2];
    int[] çeyreği = dilim[0 .. $ / 4];

    çeyreği[1] = 0;    // tek dilimde değişiklik

    writeln(çeyreği);
    writeln(yarısı);
    writeln(dilim);
}

çeyreği diliminin ikinci elemanında yapılan değişiklik asıl elemanı değiştirdiği için, bu etki dilimlerin hepsi tarafından görülür:

[1, 0]
[1, 0, 5, 7]
[1, 0, 5, 7, 9, 11, 13, 15]

Bu açıdan bakıldığında dilimlerin elemanlara paylaşımlı olarak erişim sağladıkları söylenebilir. Bu paylaşımın getirdiği bir soru işareti, dilimlerden birisine eleman eklendiğinde ne olacağıdır. Dilimler aynı asıl elemanlara erişim sağladıklarından, kısa olan dilime eklenecek elemanlar için yer yoktur. (Aksi taktirde, yeni elemanlar başka dilimlerin elemanları üzerine yazılırlar.)

D, yeni eklenen bir elemanın başka dilimlerin üzerine yazılmasına izin vermez ve uzunluğun artması için yer bulunmadığında paylaşımı sona erdirir. Yeri olmayan dilim paylaşımdan ayrılır. Bu işlem sırasında o dilimin erişim sağlamakta olduğu bütün elemanlar otomatik olarak kopyalanırlar ve uzayan dilim artık bu yeni elemanlara erişim sağlamaya başlar.

Bunu görmek için yukarıdaki programdaki çeyreği diliminin elemanını değiştirmeden önce ona yeni bir eleman ekleyelim:

    çeyreği ~= 42;    // sonunda yeni elemana yer olmadığı
                      // için bu dilim bu noktada paylaşımdan
                      // ayrılır

    çeyreği[1] = 0;   // o yüzden bu işlem diğer dilimleri
                      // etkilemez

Eklenen eleman dilimin uzunluğunu arttırdığı için dilim artık kopyalanan yeni elemanlara erişim sağlamaya başlar. çeyreği'nin elemanında yapılan değişikliğin dilim ve yarısı dilimlerini artık etkilemediği programın şimdiki çıktısında görülüyor:

[1, 0, 42]
[1, 3, 5, 7]
[1, 3, 5, 7, 9, 11, 13, 15]

Dilimin uzunluğunun açıkça arttırılması da eleman paylaşımından ayrılmasına neden olur:

    ++çeyreği.length;       // paylaşımdan ayrılır

veya

    çeyreği.length += 5;    // paylaşımdan ayrılır

Öte yandan, bir dilimin uzunluğunun kısaltılması eleman paylaşımını sonlandırmaz. Uzunluğun kısaltılması, yalnızca artık daha az elemana erişim sağlama anlamına gelir:

    int[] a = [ 1, 11, 111 ];
    int[] d = a;

    d = d[1 .. $];     // başından kısaltıyoruz
    d[0] = 42;         // elemanı dilim yoluyla değiştiriyoruz

    writeln(a);        // diğer dilimi yazdırıyoruz

Çıktısından görüldüğü gibi, d yoluyla yapılan değişiklik a'nın eriştirdiği elemanı da etkilemiştir; yani paylaşım devam etmektedir:

[1, 42, 111]

Uzunluğun başka ifadeler yoluyla kısaltılması da paylaşımı sonlandırmaz:

    d = d[0 .. $ - 1];         // sonundan kısaltmak
    --d.length;                // aynı şey
    d.length = d.length - 1;   // aynı şey

Eleman paylaşımı devam eder.

Paylaşımın sonlanıp sonlanmayacağını belirlemek için capacity

Bu konuda dikkat edilmesi gereken bir karışıklık, uzunluğun artmasının paylaşımı her zaman için sonlandırmamasıdır. En uzun olan dilimin sonunda yeni elemanlara yer bulunduğu zaman paylaşım sonlanmaz:

import std.stdio;

void main() {
    int[] dilim = [ 1, 3, 5, 7, 9, 11, 13, 15 ];
    int[] yarısı = dilim[0 .. $ / 2];
    int[] çeyreği = dilim[0 .. $ / 4];

    dilim ~= 42;      // en uzun dilime ekleniyor
    dilim[1] = 0;

    writeln(çeyreği);
    writeln(yarısı);
    writeln(dilim);
}

Çıktıda görüldüğü gibi, uzunluğu artmış olmasına rağmen en uzun olan dilime eleman eklenmesi paylaşımı sonlandırmamıştır. Yapılan değişiklik bütün dilimleri etkilemiştir:

[1, 0]
[1, 0, 5, 7]
[1, 0, 5, 7, 9, 11, 13, 15, 42]

Bir dilime yeni bir eleman eklendiğinde paylaşımın sonlanıp sonlanmayacağı capacity niteliği ile belirlenir. (Aslında capacity bir işlev olarak gerçekleştirilmiştir ancak bu ayrımın burada önemi yoktur.)

Dilime ileride eklenecek olan yeni elemanlar için önceden ayrılmış olan alana o dilimin sığası denir. capacity değerinin anlamı aşağıdaki gibidir:

Buna uygun olarak, eleman eklendiğinde paylaşımın sonlanıp sonlanmayacağı aşağıdaki gibi bir kodla belirlenebilir:

    if (dilim.capacity == 0) {
        /* Yeni bir eleman eklendiğinde bu dilimin bütün
         * elemanları başka bir yere kopyalanacaklar
         * demektir. */

        // ...

    } else {
        /* Bu dilimde yeni elemanlar için yer olabilir. Kaç
         * elemanlık yer olduğunu hesaplayalım: */
        auto kaçElemanDaha = dilim.capacity - dilim.length;

        // ...
    }

Sığayla ilgili ilginç bir durum, bütün elemanlara erişim sağlayan birden fazla dilim olduğunda ortaya çıkar. Böyle bir durumda her dilim sığası olduğunu bildirir:

import std.stdio;

void main() {
    // Bütün elemanlara eriştiren üç dilim
    int[] d0 = [ 1, 2, 3, 4 ];
    int[] d1 = d0;
    int[] d2 = d0;

    writeln(d0.capacity);
    writeln(d1.capacity);
    writeln(d2.capacity);
}

Üçünün de sığası vardır:

7
7
7

Ancak, dilimlerden birisine eleman eklendiği an diğerleri sığalarını yitirirler:

    d1 ~= 42;    // ← artık d1 en uzundur

    writeln(d0.capacity);
    writeln(d1.capacity);
    writeln(d2.capacity);

Eleman eklenen dilim en uzun dilim haline geldiğinden artık yalnızca onun sığası vardır:

0
7        ← artık yalnızca d1'in sığası var
0
Elemanlar için yer ayırmak

Hem eleman kopyalamanın hem de elemanlar için yeni yer ayırmanın az da olsa bir süre bedeli vardır. Bu yüzden, eleman eklemek pahalı bir işlem olabilir. Eleman adedinin baştan bilindiği durumlarda böyle bir bedelin önüne geçmek için tek seferde yer ayırmak mümkündür:

import std.stdio;

void main() {
    int[] dilim;

    dilim.reserve(20);
    writeln(dilim.capacity);

    foreach (eleman; 0 .. 17) {
        dilim ~= eleman;    // ← bu elemanlar taşınmazlar
    }
}
31        ← En az 20 elemanlık sığa

dilim'in elemanları ancak 31'den fazla eleman olduğunda başka bir yere taşınacaklardır.

Bütün elemanlar üzerindeki işlemler

Bu olanak hem sabit uzunluklu dizilerle hem de dilimlerle kullanılabilir.

Dizi isminden sonra yazılan içi boş [] karakterleri bütün elemanlar anlamına gelir. Bu olanak, elemanların her birisiyle yapılması istenen işlemlerde büyük kolaylık sağlar.

import std.stdio;

void main() {
    double[3] a = [ 10, 20, 30 ];
    double[3] b = [  2,  3,  4 ];

    double[3] sonuç = a[] + b[];

    writeln(sonuç);
}

Çıktısı:

[12, 23, 34]

O programdaki toplama işlemi, a ve b dizilerinin birbirlerine karşılık gelen elemanlarını ayrı ayrı toplar: önce ilk elemanlar kendi aralarında, sonra ikinci elemanlar kendi aralarında, vs. O yüzden böyle işlemlerde kullanılan dizilerin uzunluklarının eşit olmaları şarttır.

Yukarıdaki programdaki + işleci yerine; daha önce gördüğünüz +, -, *, /, %, ve ^^ aritmetik işleçlerini; ilerideki bölümlerde karşılaşacağınız ^, &, ve | ikili bit işleçlerini; ve bir dizinin önüne yazılan tekli - ve ~ işleçlerini kullanabilirsiniz.

Bu işleçlerin atamalı olanları da kullanılabilir: =, +=, -=, *=, /=, %=, ^^=, ^=, &=, ve |=.

Bu olanak yalnızca iki diziyi ilgilendiren işlemler için değildir; bir dizi yanında onun elemanlarıyla uyumlu olan bir ifade de kullanılabilir. Örneğin bir dizinin bütün elemanlarını dörde bölmek için:

    double[3] a = [ 10, 20, 30 ];
    a[] /= 4;

    writeln(a);

Çıktısı:

[2.5, 5, 7.5]

Bütün elemanlarını belirli bir değere eşitlemek için:

    a[] = 42;
    writeln(a);

Çıktısı:

[42, 42, 42]

Bu olanağın dilimlerle kullanımında hataya açık bir durum vardır. Sonuçta eleman değerlerinde bir fark görülmese bile aşağıdaki iki ifade aslında anlamsal açıdan çok farklıdır:

    dilim2 = dilim1;      // ← dilim1'in elemanlarına erişim
                          //   sağlamaya başlar

    dilim3[] = dilim1;    // ← zaten erişim sağlamakta olduğu
                          //   elemanların değerleri değişir

dilim2'nin doğrudan atama işleciyle kullanılıyor olması, onun artık dilim1'in elemanlarına erişim sağlamaya başlamasına neden olur. Oysa dilim3[] ifadesi dilim3'ün bütün elemanları anlamını taşıdığı için, onun bütün elemanlarının değerleri dilim1'in elemanlarının değerlerini alırlar. Bu yüzden, unutulan bir [] işlecinin etkisi çok büyük olabilir.

Bunu aşağıdaki programda görebiliriz:

import std.stdio;

void main() {
    double[] dilim1 = [ 1, 1, 1 ];
    double[] dilim2 = [ 2, 2, 2 ];
    double[] dilim3 = [ 3, 3, 3 ];

    dilim2 = dilim1;      // ← dilim1'in elemanlarına erişim
                          //   sağlamaya başlar

    dilim3[] = dilim1;    // ← zaten erişim sağlamakta olduğu
                          //   elemanların değerleri değişir

    writeln("dilim1 önce : ", dilim1);
    writeln("dilim2 önce : ", dilim2);
    writeln("dilim3 önce : ", dilim3);

    dilim2[0] = 42;       // ← erişimini dilim1'le paylaşmakta
                          //   olduğu eleman değişir

    dilim3[0] = 43;       // ← kendi elemanı değişir

    writeln("dilim1 sonra: ", dilim1);
    writeln("dilim2 sonra: ", dilim2);
    writeln("dilim3 sonra: ", dilim3);
}

dilim2'de yapılan değişiklik dilim1'i de etkilemiştir:

dilim1 önce : [1, 1, 1]
dilim2 önce : [1, 1, 1]
dilim3 önce : [1, 1, 1]
dilim1 sonra: [42, 1, 1]
dilim2 sonra: [42, 1, 1]
dilim3 sonra: [43, 1, 1]

Buradaki tehlike; dilim2 atanırken [] işlecinin belki de unutulmuş olmasının etkisinin, belki de o yüzden istenmeden paylaşılmaya başlanmış olan eleman değişene kadar farkedilememiş olmasıdır.

Bu gibi tehlikeler yüzünden bu işlemleri dilimlerle kullanırken dikkatli olmak gerekir.

Çok boyutlu diziler

Şimdiye kadar gördüğümüz dizi işlemlerinde eleman türü olarak hep int ve double gibi temel türler kullandık. Eleman türü olarak aslında başka türler, örneğin diziler de kullanılabilir. Böylece dizi dizisi gibi daha karmaşık topluluklar tanımlayabiliriz. Elemanlarının türü dizi olan dizilere çok boyutlu dizi denir.

Şimdiye kadar gördüğümüz dizilerin elemanlarını hep soldan sağa doğru yazmıştık. İki boyutlu dizi kavramını anlamayı kolaylaştırmak için bir diziyi bir kere de yukarıdan aşağıya doğru yazalım:

    int[] dizi = [
                   10,
                   20,
                   30,
                   40
                 ];

Kodu güzelleştirmek için kullanılan boşlukların ve fazladan satırların derleyicinin gözünde etkisiz olduklarını biliyorsunuz. Yukarıdaki dizi önceden olduğu gibi tek satırda da yazılabilirdi ve aynı anlama gelirdi.

Şimdi o dizinin her bir elemanını int[] türünde bir değerle değiştirelim:

  /* ... */ dizi = [
                     [ 10, 11, 12 ],
                     [ 20, 21, 22 ],
                     [ 30, 31, 32 ],
                     [ 40, 41, 42 ]
                   ];

Yaptığımız tek değişiklik, int yerine int[] türünde elemanlar yazmak oldu. Kodun yasal olması için eleman türünü artık int olarak değil, int[] olarak belirlememiz gerekir:

    int[][] dizi = [
                     [ 10, 11, 12 ],
                     [ 20, 21, 22 ],
                     [ 30, 31, 32 ],
                     [ 40, 41, 42 ]
                   ];

Satır ve sütunlardan oluştukları için yukarıdaki gibi dizilere iki boyutlu dizi denir.

Elemanları int dizisi olan yukarıdaki dizinin kullanımı şimdiye kadar öğrendiklerimizden farklı değildir. Her bir elemanının int[] türünde olduğunu hatırlamak ve int[] türüne uyan işlemlerde kullanmak yeter:

dizi ~= [ 50, 51 ]; // yeni bir eleman (yani dilim) ekler
dizi[0] ~= 13;      // ilk elemanına (yani ilk dilimine) ekler

Aynı dizinin şimdiki hali:

[[10, 11, 12, 13], [20, 21, 22], [30, 31, 32], [40, 41, 42], [50, 51]]

Dizinin kendisi veya elemanları sabit uzunluklu da olabilir:

    int[2][3][4] dizi;  // 2 sütun, 3 satır, 4 düzlem

Yukarıdaki tanımı iki sütunlu üç satırdan oluşan dört düzlem diye düşünebilirsiniz. Öyle bir dizi, örneğin bir macera oyununda ve her katında 2x3=6 oda bulunan 4 katlı bir bina ile ilgili bir kavram için kullanılıyor olabilir.

Örneğin öyle bir binanın ikinci katının ilk odasında bulunan eşyaların sayısı şöyle arttırılabilir:

    // ikinci katın indeksi 1'dir ve o katın ilk odasına
    // [0][0] ile erişilir
    ++eşyaSayıları[1][0][0];

Yukarıdaki söz dizimlerine ek olarak, dilim dilimi oluşturmak için new ifadesi de kullanılabilir. Aşağıdaki örnek yalnızca iki boyut belirtiyor:

import std.stdio;

void main() {
    int[][] d = new int[][](2, 3);
    writeln(d);
}

Yukarıdaki new ifadesi 2 adet 3 elemanlı dizi oluşturur ve onlara erişim sağlayan bir dilim döndürür. Çıktısı:

[[0, 0, 0], [0, 0, 0]]
Özet
Problem

Bir double dizisini başından sonuna doğru ilerleyin ve değerleri 10'dan büyük olanların değerlerini yarıya indirin. Örneğin elinizde şu dizi varsa:

    double[] dizi = [ 1, 20, 2, 30, 7, 11 ];

elemanlarının değerleri şuna dönüşsün:

[1, 10, 2, 15, 7, 5.5]

Çeşitli çözümleri olsa da, bunu yalnızca dilim olanakları ile başarmaya çalışın. İşe bütün diziye erişim sağlayan bir dilimle başlayabilirsiniz. Ondan sonra o dilimi her seferinde baş tarafından tek eleman kısaltabilir ve dilimin hep ilk elemanını kullanabilirsiniz.

Şu ifade dilimi başından tek eleman kısaltır:

        dilim = dilim[1 .. $];