18-12-2017, Saat: 01:25
(Son Düzenleme: 19-12-2017, Saat: 13:02, Düzenleyen: uparlayan.
Sebep: Örneklerde düzeltme yapıldı. "çoka" ibaresi "kolay" olarak değiştirildi. Son örneğe kullanım örneği verildi.
)
Çok geniş bir konu ve tüm yönlerini irdelemek daha uzun bir yazının konusu, umarım basite indirgeyebiliriz.
Bu yazıda daha çok, Pascal'daki Array kavramının ne olduğunu, nasıl tanımlandığını, klasik kullanım örneklerini ve işimizi basitleştirecek bazı ufak tefek fonksiyon önerilerini inceleyeceğiz. Fakat Array'larla ilgili pointer ve heap gibi mekanizmalara ve kompleks veri tipleriyle (class, generics vb...) nasıl kullanıldığına dair konulara değinmeyeceğiz. Bunlar daha ileri konular ve asıl konu başlı başına geniş bir içeriğe sahip olduğu için anlatımı dağıtma potansiyeline sahipler, o nedenle belki başka bir makalede bunlara değiniriz. Örneklerimizi basit veri türleri ile sınırlandıracağız ve performans ile ilgili konulara girmeyeeğiz, sadece nedir, nasıl kullanılır sorularının etrafında dolaşacağız. Bununla birlikte Arrayları kullanırken sadece basit (veya basitleştirilmiş) veri tipleriyle (byte, integer, char, TDateTime, Double, currency, string gibi) sınırlı olmadığınızı bilmeniz yararlı olur.
Girizgaha matematik ile başlayalım; Net bir tanımı olmamasına rağmen Matematikteki küme kavramı tarif edilirken "Belirli özelliğe sahip olan nesneler topluluğu" ifadesi kullanılır. Array'ları da bu çerçeveden ele alırsak bellekte oluşturduğumuz kümeler olarak düşünebiliriz. Buna göre; Aynı veri tipine sahip (aynı türde olmak zorunda da değil) değerler kümesini topluca yönetebildiğimiz, bir kolleksiyon olarak ele alabildiğimiz yapılara dizi, yani "Array" diyoruz. Değişken olarak tanımlayabildiğimiz herşeyi birer dizi olarak da tanımlayabiliriz. Çünkü Dizilerin kendisi de aslında ve aynı zamanda birer veri tipidir. Kümeyi oluşturan nesnelere kümenin "elemanları" denir. Aynı şekilde Array'lar da elemanlardan oluşur ve her bir elemanın bir indis değeri vardır. Bu indis değerini kullanarak Array'ın elemanları (Item'leri) arasında gezinebiliriz.
Pascal'da üç tip Array tanımı vardır. Bunlar durağan, sabit, yani "Statik Array" tipi, bunun tam tersi olan, çalışma zamanında boyunu anlık olarak değiştirebileceğimiz "Dinamic Array" tipi ve son olarak fonksiyon ve prosedürlere parametre olarak iletebildiğimiz Açık Dizi / Open Array'lar vardır. Boyut açısından ise tek boyutlu Array'lar ve çok boyutlu arraylar olarak ikiye ayırmak sanırım daha doğru bir yaklaşım olabilir.
Kısaca Array'ları tanıdığımıza göre artık sade ve basit misallerle yazımızı örneklendirmeye başlayabiliriz.
STATIK ARRAY / SABİT DİZİLER
Yukarıda kısaca değindiğimiz gibi bu tür diziler çalışma anındayken eleman sayısı değiştirilemeyen dizilerdir. Eleman sayısı açısından nasıl tanımlanmışlarsa o sınırlar içerisinde kullanılırlar. Eleman sayısı sabittir ve çalışma anında eleman sayısı değiştirilemez, bunun temel bir sebebi vardır, o da bu tür dizilere ayrılan bellek bölgesinin sabit olmasından kaynaklanır.
Bunun dışında başlangıç indis değeri statik dizilerde rahatlıkla belirlenebilir. Biz örneklerimizde "[0..9]" şeklinde bir kullanım sergiledik fakat bir statik dizi için bu böyle olmak zorunda değil, mesela "[5..10000]" veya "[-41..94]" gibi de tanımlanabilir. Buradaki ana belirleyici unsur, sizin indis değerini baz aldığınız durumları yönetmeye ihtiyacınızın olup olmadığıdır...
Aşağıdaki örnekte basit bir statik dizi tanımı yapılmaktadır;
Yukarıda "BiDizi" adında, toplamda (yani sıfır da dahil olmak üzere) "10" adet elemanı olan ve veri tipi INTEGER olan bir dizi tanımlamış olduk. Bu tanıma göre bu dizideki elemanlara nasıl erişeceğimizin de bir örneğini vermek, konunun anlaşılması açısından yardımcı olabilir;
Dikkat ettiyseniz dizimizin ilk elemanı "0" ile ifade ediliyor. Eğer tanımı şu şekilde yapsaydık;
Bu diziyi BiDizi[0] şekilde kullandığımızda derleyici bize "sıfır" indisli bir dizi elemanı olmadığı için "E1012 Constant expression violates subrange bounds" şeklinde bir hata mesajı verecekti...
Konuya geri dönecek olursak, diziler sadece bir değişken olarak tanımlanmak zorunda değildir. Statik Dizileri bir sabit veya bir tip olarak da tanımlamak mümkündür;
Bir değişken olarak tanımlayacağımız zaman;
Bir tip olarak tanımlayacağımız zaman;
Ve dizimizin boyutunun sabit olduğu gibi, içeriğinin de sabit olmasını istiyorsak bunu bir sabit olarak da tanımlayabiliriz, şöyle;
Tabi böyle bir tanımlama yaptığımızda dizimiz çalışma anındayken değiştirilemez (readonly) bir nitelik kazanacaktır.
ufak bir kullanım örneğiyle bu kısmı bitirip Dinamik arraylara geçebiliriz;
DYNAMIC ARRAY - DİNAMİK DİZİLER
Adından da anlaşılacağı üzere bu Array tipi çalışma zamanında eleman sayısı değiştirilebilen, dolayısıyla bellekte genişleyip daralabilen dizilerdir. Dinamik diziler tanımlandığı sırada kullanacağı veri tipini belirtir fakat herhangi bir eleman sayısı bilgisine bildirmeyiz. Dinamik bir diziye bir değer atadığımızda (yani onu bir değişkenmiş gibi kullandığımızda) veya onu SetLength yordamına maruz bıraktığımızda, dinamik dizimiz için bellek yeniden ayarlanır. Dinamik diziyi bir değişken olarak kullanmayıp, doğrudan elemanlarını işlemek istediğimizde henüz bellekte kendine ait bir bölge olmadığı için diziyi "ilklendirmeliyiz". Yani "SetLength(BiDizi, 15)" komutu kullanılarak diziye bellekte kaç (örnekte 15) elemanlık bellek ayrılması gerektiğini belirtiriz. Bu durumda belleğin, bir kısmı, bu dizi için tahsis edilir. Bellekteki bu aktivitenin nasıl işlediği, mekanizmanın nasıl olduğu gibi konular bu yazının kapsamını dağıtmamak adına değinilmeyecek. Bu tarz, bellek mekanizmasına dair mevzular muhtemelen yorumlar kısmında diğer arkadaşlarım tarafından değinilecektir diye tahmin ediyorum.
Dinamik dizilerde indis belirtilemez, dolayısıyla bu tip dizilerde indis her zaman "0" ile başlar ve negatif bir değer alamaz. Bu nedenle her zaman toplam eleman sayısı, eksi bir, olacak şekilde dizi elemanları arasında dolaşmamız gerekir. Aşağıdaki bir kaç örnek sanırım bunu açıklamaya yardımcı olacaktır;
Setlength kullanımına alternatif olarak doğrudan küme ifadesi de kullanılabilir;
OPEN ARRAY - AÇIK DİZİLER
Yukarıdaki örnek kodda dizilerimizi bir değişken olarak tanımladık ve aynı veri tipinde olmalarına rağmen aslen pek de gerçekçi bir örnek olmadığını gördük. Gördük çünkü değişkenlerimizi ve tiplerimizi fiiliyatta tek bir noktada tanımlamayabiliyoruz. Bu sorunu aşmak için kullandığımız diziye özel veri tipleri tanımlayabiliriz. Hemen örnek verelim;
Görüldüğü üzere bir önceki örnekte BiDizi ve DiziDegiskeni adlı değişkenlerimizi tanımlarken araya virgül katmamız gerekmiş idi, şimdiki örnekte ise böyle bir kısıtlamaya maruz kalmamış olduk. Biz, bu tür bir tanımlamaya OPEN ARRAY / AÇIK DİZİ diyoruz.
Açık dizileri, derleme zamanında elemanları henüz belirlenmemiş olan diziler olarak da düşünebiliriz. Açık dizileri dinamik dizilerden ayıran temel unsur açık dizilerin bir veri tipi olarak tanımlanmasından kaynaklanıyor. Şöyleki; Diziler parametre olarak da kullanılabilirler. Dizi parametresinin belli bir indis aralığı veya sınırı yoksa (veya istenen şey aslında dinamik bir dizi ise) bunu doğrudan değil, dolaylı olarak parametize ederiz. Bu tip dizilere AÇIK DİZİ / OPEN ARRAY denir ve "var" kısmında değil, "type" kısmında bir tip olarak tanımlanır. Delphi, açık dizilerin bellekte ne kadar yer kaplayacağını "örtülü olarak" kendisi arka tarafta yönetir. Yani setlength ile bir AÇIK ARRAY'ın kaç elemana sahip olacağını siz söylemezsiniz, bunu Delphi arka tarafta kendisi otomatik olarak yapar.
Açık dizilerin kullanımı ile ilgili alternatif olarak Create oluşturucusu da kullanılabilir; Mesela;
veya çok daha kısa bir yöntem, doğrudan küme değerlerini girmek şeklinde de olabilir;
Fakat çıkarma "-" operatörünü kullanamazsınız. Bunun yerine Delete metodu kullanılabilir;
MULTI-DIMENSIONAL ARRAY'LAR - ÇOK BOYUTLU DİZİLER
Basit anlamda sade, statik bir dizinin, dinamik bir dizinin ve açık bir dizinin hangi yöntemlerle tanımlanabileceğini gördüğümüze göre çok boyutlu dizilerin nasıl tanımlanabileceğini de inceleyebiliriz. Gerek Statik, gerek dinamik, gerekse de açık dizi olsun, bir diziyi çok boyutlu yapan şey, bir eleman için birden çok indisin tanımlanabilmesidir.
Örneklemeyi Statik Arraylar için konuşacak olursak onları tanımlarken "[0..9]" gibi bir indis sınırlaması belirliyorduk. Bunu iki boyutlu yapmak için bir indis sınırı daha belirtmemiz gerekir, yani "[0..9 , 1..2]" gibi... Virgülden sonraki "1..2" ibaresi, bizim ikinci boyutumuzu temsil eden indis sınırını göstermektedir. Bu şekilde, araya virgüller katarak daha çok indis (yani daha çok boyut) ekleyebiliriz. Bunu aşağıdaki örnekle daha iyi anlatabileceğimi sanıyorum;
Görüldüğü üzere açıklama satırında "A" ile temsil edilen kısım 1. boyutu, "B" 2. boyutu, "C" ise 3. boyutu temsil etmektedir. Bu yapıları bellekte basit bir veri tablosu olarak da düşünebilirsiniz. Bu tip dizileri kullanmak için aşağıdaki örneği inceleyebiliriz;
Benzer bir yapıyı dinamik olarak da tanımlayabiliriz. Dinamik bir çok boyutlu dizi tanımı statik bir, çok boyutlu diziden tanımı itibariyle daha esnek olabilmektedir. Bunu bir örnekle göstermek sanırım daha kolay olacak;
Fakat dinamik dizilerde bu kadar esnek davranmamıza gerek olmadığında çoklu dizimizin eleman sayısını şöyle de tanımlayabilirdik;
ARRAY ve NESNE KULLANIMI
Her ne kadar yazının başında kompleks veri tiplerine değinmeyeceğimizi söylemiş olsak da mevzuya bir kenarından dokunmazsak konu eksik kalır çekincesini taşıyorum, o nedenle yine basite indirgemek adına RECORD tipindeki bir yapının bir array içinde nasıl kullanılabileceğine dair ufak bir örnek vermek sanırım yeterli olur. Aşağıdaki örneği bir CLASS için de kullanmak mümkündür, sonuçta (neredeyse) herşey bir pointer olduğuna göre bunu bu şekilde kullanmaya da bir engel yok sanırım...
UFAK BİR ÖRNEK
Her ne kadar yazının kısa olmasını istesem de buraya kadar okuma sabrını gösterdiğiniz için teşekkürler. Yazının bundan sonrası için arraylarla ilgili bazı örnekler üzerinde duracağız. Array konusu çok kapsamlı ve geniş bir konu, yazdıkça yenileri ortaya çıkıyor ve Delphi Array'larla ilgili zamanın verdiği birikim nedeniyle çok geniş bir yetenek kolleksiyonuna sahip. Aşağıdaki örnek fonksiyonlar bir dizide belirtilen bir elemanın varsa hangi indiste olduğunu söylüyorlar. Bunların overload'ları çeşitlendirilebilir veya generics bir tip tanımı üzerinden daha gelişmiş örnekler haline de getirilebilir, örnek olması açısından incelemenize sunuyorum.
(EKLEME) Aşağıdaki örnek aynı zamanda AÇIK DİZİ'lerin (OPEN ARRAY) parametre olarak nasıl kullanılabildiğini ve boş parametre veya varsayılan parametreleri nasıl verebileceğimizi de ayrıca göstermesi açısından tamamlayıcı niteliktedir.
Kullanımı da şöyle olabilir;
Array konusu çok geniş ve bu yazı burada bitmez ama bir yerde dur demek lazım. Faydalı olması dileğiyle...
Bu yazıda daha çok, Pascal'daki Array kavramının ne olduğunu, nasıl tanımlandığını, klasik kullanım örneklerini ve işimizi basitleştirecek bazı ufak tefek fonksiyon önerilerini inceleyeceğiz. Fakat Array'larla ilgili pointer ve heap gibi mekanizmalara ve kompleks veri tipleriyle (class, generics vb...) nasıl kullanıldığına dair konulara değinmeyeceğiz. Bunlar daha ileri konular ve asıl konu başlı başına geniş bir içeriğe sahip olduğu için anlatımı dağıtma potansiyeline sahipler, o nedenle belki başka bir makalede bunlara değiniriz. Örneklerimizi basit veri türleri ile sınırlandıracağız ve performans ile ilgili konulara girmeyeeğiz, sadece nedir, nasıl kullanılır sorularının etrafında dolaşacağız. Bununla birlikte Arrayları kullanırken sadece basit (veya basitleştirilmiş) veri tipleriyle (byte, integer, char, TDateTime, Double, currency, string gibi) sınırlı olmadığınızı bilmeniz yararlı olur.
Girizgaha matematik ile başlayalım; Net bir tanımı olmamasına rağmen Matematikteki küme kavramı tarif edilirken "Belirli özelliğe sahip olan nesneler topluluğu" ifadesi kullanılır. Array'ları da bu çerçeveden ele alırsak bellekte oluşturduğumuz kümeler olarak düşünebiliriz. Buna göre; Aynı veri tipine sahip (aynı türde olmak zorunda da değil) değerler kümesini topluca yönetebildiğimiz, bir kolleksiyon olarak ele alabildiğimiz yapılara dizi, yani "Array" diyoruz. Değişken olarak tanımlayabildiğimiz herşeyi birer dizi olarak da tanımlayabiliriz. Çünkü Dizilerin kendisi de aslında ve aynı zamanda birer veri tipidir. Kümeyi oluşturan nesnelere kümenin "elemanları" denir. Aynı şekilde Array'lar da elemanlardan oluşur ve her bir elemanın bir indis değeri vardır. Bu indis değerini kullanarak Array'ın elemanları (Item'leri) arasında gezinebiliriz.
Pascal'da üç tip Array tanımı vardır. Bunlar durağan, sabit, yani "Statik Array" tipi, bunun tam tersi olan, çalışma zamanında boyunu anlık olarak değiştirebileceğimiz "Dinamic Array" tipi ve son olarak fonksiyon ve prosedürlere parametre olarak iletebildiğimiz Açık Dizi / Open Array'lar vardır. Boyut açısından ise tek boyutlu Array'lar ve çok boyutlu arraylar olarak ikiye ayırmak sanırım daha doğru bir yaklaşım olabilir.
Kısaca Array'ları tanıdığımıza göre artık sade ve basit misallerle yazımızı örneklendirmeye başlayabiliriz.
STATIK ARRAY / SABİT DİZİLER
Yukarıda kısaca değindiğimiz gibi bu tür diziler çalışma anındayken eleman sayısı değiştirilemeyen dizilerdir. Eleman sayısı açısından nasıl tanımlanmışlarsa o sınırlar içerisinde kullanılırlar. Eleman sayısı sabittir ve çalışma anında eleman sayısı değiştirilemez, bunun temel bir sebebi vardır, o da bu tür dizilere ayrılan bellek bölgesinin sabit olmasından kaynaklanır.
Bunun dışında başlangıç indis değeri statik dizilerde rahatlıkla belirlenebilir. Biz örneklerimizde "[0..9]" şeklinde bir kullanım sergiledik fakat bir statik dizi için bu böyle olmak zorunda değil, mesela "[5..10000]" veya "[-41..94]" gibi de tanımlanabilir. Buradaki ana belirleyici unsur, sizin indis değerini baz aldığınız durumları yönetmeye ihtiyacınızın olup olmadığıdır...
Aşağıdaki örnekte basit bir statik dizi tanımı yapılmaktadır;
var BiDizi : Array [0..9] of integer;
Yukarıda "BiDizi" adında, toplamda (yani sıfır da dahil olmak üzere) "10" adet elemanı olan ve veri tipi INTEGER olan bir dizi tanımlamış olduk. Bu tanıma göre bu dizideki elemanlara nasıl erişeceğimizin de bir örneğini vermek, konunun anlaşılması açısından yardımcı olabilir;
var BiDizi : Array [0..9] of integer; I: Integer; begin BiDizi[0] := 1; BiDizi[1] := 2; BiDizi[2] := 3; BiDizi[3] := 4; BiDizi[4] := 5; BiDizi[5] := 6; BiDizi[6] := 7; BiDizi[7] := 8; BiDizi[8] := 9; BiDizi[9] := 10; // Başka bir örnek; for I := 0 to 9 do BiDizi[I] := I + 1; // Diğer bir örnek; for I in BiDizi do begin BiDizi[I] := I * 2; Memo1.Lines.Add(BiDizi[I].ToString); end; // Daha başka bir örnek for I := Low(BiDizi) to High(BiDizi) do begin BiDizi[I] := I div 2; Memo1.Lines.Add(BiDizi[I].ToString); end; end;
Dikkat ettiyseniz dizimizin ilk elemanı "0" ile ifade ediliyor. Eğer tanımı şu şekilde yapsaydık;
var BiDizi : Array [5..9] of integer; // veya > of string; of char; of Currency; of TDateTime; // vs...
Bu diziyi BiDizi[0] şekilde kullandığımızda derleyici bize "sıfır" indisli bir dizi elemanı olmadığı için "E1012 Constant expression violates subrange bounds" şeklinde bir hata mesajı verecekti...
Konuya geri dönecek olursak, diziler sadece bir değişken olarak tanımlanmak zorunda değildir. Statik Dizileri bir sabit veya bir tip olarak da tanımlamak mümkündür;
Bir değişken olarak tanımlayacağımız zaman;
var BiDizi : Array [0..9] of Integer;
Bir tip olarak tanımlayacağımız zaman;
type TDizi = Array [0..9] of integer; // devamıdır; var BiDizi: TDizi;
Ve dizimizin boyutunun sabit olduğu gibi, içeriğinin de sabit olmasını istiyorsak bunu bir sabit olarak da tanımlayabiliriz, şöyle;
const BiDizi : Array [0..9] of Integer = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // veya başka bir veri tipiyle daha anlaşılır başka bir örnek Aylar : Array [1..12] of String = ('Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık');
Tabi böyle bir tanımlama yaptığımızda dizimiz çalışma anındayken değiştirilemez (readonly) bir nitelik kazanacaktır.
ufak bir kullanım örneğiyle bu kısmı bitirip Dinamik arraylara geçebiliriz;
const Aylar : Array [1..12] of String = ('Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'); begin for I := Low(Aylar) to High(Aylar) do Memo1.Lines.Add( Aylar[I] ); end;
DYNAMIC ARRAY - DİNAMİK DİZİLER
Adından da anlaşılacağı üzere bu Array tipi çalışma zamanında eleman sayısı değiştirilebilen, dolayısıyla bellekte genişleyip daralabilen dizilerdir. Dinamik diziler tanımlandığı sırada kullanacağı veri tipini belirtir fakat herhangi bir eleman sayısı bilgisine bildirmeyiz. Dinamik bir diziye bir değer atadığımızda (yani onu bir değişkenmiş gibi kullandığımızda) veya onu SetLength yordamına maruz bıraktığımızda, dinamik dizimiz için bellek yeniden ayarlanır. Dinamik diziyi bir değişken olarak kullanmayıp, doğrudan elemanlarını işlemek istediğimizde henüz bellekte kendine ait bir bölge olmadığı için diziyi "ilklendirmeliyiz". Yani "SetLength(BiDizi, 15)" komutu kullanılarak diziye bellekte kaç (örnekte 15) elemanlık bellek ayrılması gerektiğini belirtiriz. Bu durumda belleğin, bir kısmı, bu dizi için tahsis edilir. Bellekteki bu aktivitenin nasıl işlediği, mekanizmanın nasıl olduğu gibi konular bu yazının kapsamını dağıtmamak adına değinilmeyecek. Bu tarz, bellek mekanizmasına dair mevzular muhtemelen yorumlar kısmında diğer arkadaşlarım tarafından değinilecektir diye tahmin ediyorum.
Dinamik dizilerde indis belirtilemez, dolayısıyla bu tip dizilerde indis her zaman "0" ile başlar ve negatif bir değer alamaz. Bu nedenle her zaman toplam eleman sayısı, eksi bir, olacak şekilde dizi elemanları arasında dolaşmamız gerekir. Aşağıdaki bir kaç örnek sanırım bunu açıklamaya yardımcı olacaktır;
var BiDizi, DiziDegiskeni : Array of Integer; I: Integer; begin SetLength(BiDizi, 5); // BiDizi adlı dizinin eleman sayısını burada belirttiğimize dikkat edin. memo1.Clear; for I := Low(BiDizi) to High(BiDizi) do begin BiDizi[I] := I; Memo1.Lines.Add( BiDizi[I].ToString ); end; DiziDegiskeni := BiDizi; // DiziDegiskeni'ni SETLENGTH ile ayarlamadığımıza, "DiziDegiskeni"'ni bir "değişken" olarak kullandığımıza dikkat edin... for I := Low(DiziDegiskeni) to High(DiziDegiskeni) do begin BiDizi[I] := I; Memo1.Lines.Add( DiziDegiskeni[I].ToString ); end; end;
Setlength kullanımına alternatif olarak doğrudan küme ifadesi de kullanılabilir;
var BiDizi: Array of Integer; begin BiDizi := [1,2,3,4,5,6,7,8]; // doğrudan 8 elemanlı bir dinamik dizi oluşturmuş olduk. end;
OPEN ARRAY - AÇIK DİZİLER
Yukarıdaki örnek kodda dizilerimizi bir değişken olarak tanımladık ve aynı veri tipinde olmalarına rağmen aslen pek de gerçekçi bir örnek olmadığını gördük. Gördük çünkü değişkenlerimizi ve tiplerimizi fiiliyatta tek bir noktada tanımlamayabiliyoruz. Bu sorunu aşmak için kullandığımız diziye özel veri tipleri tanımlayabiliriz. Hemen örnek verelim;
type TDiziTipim = array of integer; TAylar = array [1..12] of string; //... var BiDizi : TDiziTipim; DiziDegiskeni : TDiziTipim; Aylar : TAylar;
Görüldüğü üzere bir önceki örnekte BiDizi ve DiziDegiskeni adlı değişkenlerimizi tanımlarken araya virgül katmamız gerekmiş idi, şimdiki örnekte ise böyle bir kısıtlamaya maruz kalmamış olduk. Biz, bu tür bir tanımlamaya OPEN ARRAY / AÇIK DİZİ diyoruz.
Açık dizileri, derleme zamanında elemanları henüz belirlenmemiş olan diziler olarak da düşünebiliriz. Açık dizileri dinamik dizilerden ayıran temel unsur açık dizilerin bir veri tipi olarak tanımlanmasından kaynaklanıyor. Şöyleki; Diziler parametre olarak da kullanılabilirler. Dizi parametresinin belli bir indis aralığı veya sınırı yoksa (veya istenen şey aslında dinamik bir dizi ise) bunu doğrudan değil, dolaylı olarak parametize ederiz. Bu tip dizilere AÇIK DİZİ / OPEN ARRAY denir ve "var" kısmında değil, "type" kısmında bir tip olarak tanımlanır. Delphi, açık dizilerin bellekte ne kadar yer kaplayacağını "örtülü olarak" kendisi arka tarafta yönetir. Yani setlength ile bir AÇIK ARRAY'ın kaç elemana sahip olacağını siz söylemezsiniz, bunu Delphi arka tarafta kendisi otomatik olarak yapar.
Açık dizilerin kullanımı ile ilgili alternatif olarak Create oluşturucusu da kullanılabilir; Mesela;
type TDizi = array of Integer; var BiDizi: TDizi; begin BiDizi := TDizi.Create(3,5,7,9,11 {...}); end;
veya çok daha kısa bir yöntem, doğrudan küme değerlerini girmek şeklinde de olabilir;
... begin BiDizi := [1,2,3,4,5,6,7,89,9]; end;Açık dizileri birbiriyle toplamak da mümkündür; Bunun için örnekteki gibi "+" operatörü veya "concat" fonksiyonu alternatif olarak kullanılabilir;
type TDizi = array of Integer; var BiDizi, DigerDizi: TDizi; I: Integer; begin BiDizi := [1,3,5,7,9]; DigerDizi := Bidizi + [2,4,6,8]; for I := Low(DigerDizi) to High(DigerDizi) do Memo1.Lines.Add(DigerDizi[I].ToString); Memo1.Text := Memo1.Text + #13#10; DigerDizi := Concat(DigerDizi, [55,56], [100,200]); for I := Low(DigerDizi) to High(DigerDizi) do Memo1.Text := Memo1.Text + ', ' + DigerDizi[I].ToString; end;
Fakat çıkarma "-" operatörünü kullanamazsınız. Bunun yerine Delete metodu kullanılabilir;
... Delete(DigerDizi, 0, 2); for I := Low(DigerDizi) to High(DigerDizi) do Memo1.Lines.Add(DigerDizi[I].ToString); end;
MULTI-DIMENSIONAL ARRAY'LAR - ÇOK BOYUTLU DİZİLER
Basit anlamda sade, statik bir dizinin, dinamik bir dizinin ve açık bir dizinin hangi yöntemlerle tanımlanabileceğini gördüğümüze göre çok boyutlu dizilerin nasıl tanımlanabileceğini de inceleyebiliriz. Gerek Statik, gerek dinamik, gerekse de açık dizi olsun, bir diziyi çok boyutlu yapan şey, bir eleman için birden çok indisin tanımlanabilmesidir.
Örneklemeyi Statik Arraylar için konuşacak olursak onları tanımlarken "[0..9]" gibi bir indis sınırlaması belirliyorduk. Bunu iki boyutlu yapmak için bir indis sınırı daha belirtmemiz gerekir, yani "[0..9 , 1..2]" gibi... Virgülden sonraki "1..2" ibaresi, bizim ikinci boyutumuzu temsil eden indis sınırını göstermektedir. Bu şekilde, araya virgüller katarak daha çok indis (yani daha çok boyut) ekleyebiliriz. Bunu aşağıdaki örnekle daha iyi anlatabileceğimi sanıyorum;
var ikiboyutluStatikBirDizi: Array [0..9 , 1..2] of integer; UcBoyutluStatikBirDizi : Array [0..9 , 1..2 , 0..5] of integer; // [ A , B , C ]
Görüldüğü üzere açıklama satırında "A" ile temsil edilen kısım 1. boyutu, "B" 2. boyutu, "C" ise 3. boyutu temsil etmektedir. Bu yapıları bellekte basit bir veri tablosu olarak da düşünebilirsiniz. Bu tip dizileri kullanmak için aşağıdaki örneği inceleyebiliriz;
var Dizi_2D : Array [0..9 , 0..9] of integer; A, B : Integer; begin WriteLn('Çarpım Tablosu'); for a := 0 to 9 do begin for b := 0 to 9 do begin Dizi_2D[a, b] := a * b; WriteLn( a.ToString + ' x ' + B.ToString + ' = ' + Dizi_2D[a, b].ToString ) end; end; end;
Benzer bir yapıyı dinamik olarak da tanımlayabiliriz. Dinamik bir çok boyutlu dizi tanımı statik bir, çok boyutlu diziden tanımı itibariyle daha esnek olabilmektedir. Bunu bir örnekle göstermek sanırım daha kolay olacak;
var ikiBoyutluDinamikBirDizi : Array of Array of Integer; // Çok Boyutlu dizi / Array // "1. boyut" "2. boyut" veri tipi A, B : Integer; begin SetLength(ikiBoyutluDinamikBirDizi, 3); // iki boyutlu Arrayımızın ilk boyutunu 3 elemanlı olacak şekilde ayarladık. // Esneklikten kastım aşağıdaki 3 satırlık kodda açıkça görülebilir. SetLength(ikiBoyutluDinamikBirDizi[0], 4); // iki boyutlu dizimizin ilk elemanında yer alan alt diziyi 4 elemanlı olacak şekilde ayarladık. SetLength(ikiBoyutluDinamikBirDizi[1], 3); // iki boyutlu dizimizin ikinci elemanında yer alan alt diziyi 3 elemanlı olacak şekilde ayarladık. SetLength(ikiBoyutluDinamikBirDizi[2], 2); // iki boyutlu dizimizin son elemanında yer alan alt diziyi 2 elemanlı olacak şekilde ayarladık. // İki boyutlu dizimizin tüm elemanlarının değerlerini ayarlayalım ve içeriğini yazdıralım... for A := 0 to High(ikiBoyutluDinamikBirDizi) do for B := 0 to High(ikiBoyutluDinamikBirDizi[A]) do begin ikiBoyutluDinamikBirDizi[A, B] := A + B; WriteLn( 'ikiBoyutluDinamikBirDizi[' + A.ToString + ',' + B.ToString + '] = ' + ikiBoyutluDinamikBirDizi[A, B].toString ); end; end;
Fakat dinamik dizilerde bu kadar esnek davranmamıza gerek olmadığında çoklu dizimizin eleman sayısını şöyle de tanımlayabilirdik;
var ikiBoyutluDinamikBirDizi : Array of Array of Integer; // Çok Boyutlu dizi / Array // "1. boyut" "2. boyut" veri tipi A, B : Integer; begin SetLength(ikiBoyutluDinamikBirDizi, 3, 5); // iki boyutlu Arrayımızın ilk boyutunu 3 elemanlı, alt array'ların her birini ise 5'er elemanlı olacak şekilde de ayarlayabiliriz. Dizideki hücrelere ise bir önceki örnekte yer alan for döngüleri ile de erişilebilir.
ARRAY ve NESNE KULLANIMI
Her ne kadar yazının başında kompleks veri tiplerine değinmeyeceğimizi söylemiş olsak da mevzuya bir kenarından dokunmazsak konu eksik kalır çekincesini taşıyorum, o nedenle yine basite indirgemek adına RECORD tipindeki bir yapının bir array içinde nasıl kullanılabileceğine dair ufak bir örnek vermek sanırım yeterli olur. Aşağıdaki örneği bir CLASS için de kullanmak mümkündür, sonuçta (neredeyse) herşey bir pointer olduğuna göre bunu bu şekilde kullanmaya da bir engel yok sanırım...
type TUrun = packed record UrunAdi : String; Fiyat : Currency; end; const Urunler: Array[0..2] of TUrun = ( ( UrunAdi : 'Kitap' ; Fiyat : 50.00 ) , ( UrunAdi : 'Defter' ; Fiyat : 10.00 ) , ( UrunAdi : 'Kalem' ; Fiyat : 2.50 ) ); implementation {$R *.dfm} uses System.SysUtils; procedure TForm1.Button1Click(Sender: TObject); var Mallar: Array[0..2] of TUrun; I: Integer; begin Mallar[0].UrunAdi := 'Kitap'; Mallar[0].Fiyat := 50.00; Mallar[1].UrunAdi := 'Defter'; Mallar[1].Fiyat := 10.00; Mallar[2].UrunAdi := 'Kalem'; Mallar[2].Fiyat := 2.50; //Urunler[0].UrunAdi := 'BU BİR CONST OLDUĞU İÇİN HATA VERİR'; for I := Low(Mallar) to High(Mallar) do Memo1.Lines.Add('Mallar > ' + Mallar[I].UrunAdi + ' (' + floatToStr (Mallar[I].Fiyat) + ' TL)'); for I := Low(Urunler) to High(Urunler) do Memo1.Lines.Add('Urunler > ' + Urunler[I].UrunAdi + ' (' + floatToStr (Urunler[I].Fiyat) + ' TL)'); end;
UFAK BİR ÖRNEK
Her ne kadar yazının kısa olmasını istesem de buraya kadar okuma sabrını gösterdiğiniz için teşekkürler. Yazının bundan sonrası için arraylarla ilgili bazı örnekler üzerinde duracağız. Array konusu çok kapsamlı ve geniş bir konu, yazdıkça yenileri ortaya çıkıyor ve Delphi Array'larla ilgili zamanın verdiği birikim nedeniyle çok geniş bir yetenek kolleksiyonuna sahip. Aşağıdaki örnek fonksiyonlar bir dizide belirtilen bir elemanın varsa hangi indiste olduğunu söylüyorlar. Bunların overload'ları çeşitlendirilebilir veya generics bir tip tanımı üzerinden daha gelişmiş örnekler haline de getirilebilir, örnek olması açısından incelemenize sunuyorum.
(EKLEME) Aşağıdaki örnek aynı zamanda AÇIK DİZİ'lerin (OPEN ARRAY) parametre olarak nasıl kullanılabildiğini ve boş parametre veya varsayılan parametreleri nasıl verebileceğimizi de ayrıca göstermesi açısından tamamlayıcı niteliktedir.
type TArrayStr = array of string; TArrayInt = array of Integer; TArrayVar = array of Variant; ... function Exists(aAranan: String; aDizi: TArrayStr = []): Integer; overload; function Exists(aAranan: Integer; aDizi: TArrayInt = []): Integer; overload; function Exists(aAranan: Variant; aDizi: TArrayVar = []): Integer; overload; Implementation function Exists(aAranan: String; aDizi: TArrayStr = []): Integer; var I: Integer; begin Result := -1; for I := Low(aDizi) to High(aDizi) do if (aDizi[I] = aAranan) then begin Result := I; Break; end; end; function Exists(aAranan: Integer; aDizi: TArrayInt = []): Integer; var I: Integer; begin Result := -1; for I := Low(aDizi) to High(aDizi) do if (aDizi[I] = aAranan) then begin Result := I; Break; end; end; function Exists(aAranan: Variant; aDizi: TArrayVar = []): Integer; overload; var I: Integer; begin Result := -1; for I := Low(aDizi) to High(aDizi) do if ( VarType(aDizi[I]) = VarType(aAranan)) then begin if (aDizi[I] = aAranan) then begin Result := I; Break; end; end; end;
Kullanımı da şöyle olabilir;
if Exists( 55.72, ['test', 12, 55, 72, true, 55.72, 'metin']) > -1 then ShowMessage('Eleman dizide mevcut'); // veya ShowMessage ( Exists(null, ['', null, varEmpty, 0]).ToString ); // 1. indiste null değerini bulacaktır... // veya elemanımız var fakat dizinin içi boş olsun; ShowMessage( Exists(33, []).ToString ); // bulunamayacağı için -1 üretecektir.
Array konusu çok geniş ve bu yazı burada bitmez ama bir yerde dur demek lazım. Faydalı olması dileğiyle...
YouTube Delphi Tips
"Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır" Peyami Safa
"Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır" Peyami Safa