Forum: D Programlama Dili RSS
Dizilerle ilgili bir soru
cos00kun #1
Üye Kas 2014 tarihinden beri · 104 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Dizilerle ilgili bir soru
şöyle bir kodumuz var;
1 import std.stdio;
2 import std.algorithm;
3 void main(string[] argv)
4 {
5    int[5] dizibes=[8,2,0,7,5];
6    int[5] dizialti=[9,3,6,1,4];
7    int[] dizitoplam=dizibes~dizialti;
8    writeln("ikisini topladım ve sıraladım.....",sort(dizitoplam));
9    writeln("5.elemanı çıkarttım ve yazdırdım..",dizitoplam.remove(5));
10   writeln("Tekrar yazdırdım..................",dizitoplam);
11   readln();
12 }

ve çıkan sonuç;

ikisini topladım ve sıraladım.....[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5.elemanı çıkarttım ve yazdırdım..[0, 1, 2, 3, 4, 6, 7, 8, 9]
Tekrar yazdırdım..................[0, 1, 2, 3, 4, 6, 7, 8, 9, 9]
şimdi burada programın 9 ve 10 satırındaki kodun aynı sonucunu bekliyordum açıkçası neden böyle bir sonuç verdiğini anlayamadım.. belki C++ alışkınlığından belki bir başka sebepten bilemiyorum ancak normalde "dizitoplam.remove(5)" i yazdırdığımızda zaten "dizitoplam" ı yazdırmış olmuyormuyuzki ikinci "dizitoplam" da farklı bir netice çıksın ??

konuyla ilgili Ali beyin kitapta yazdığı gibi removenin dizi boyutunu değiştirmediğini saedece aradan çekip kaydırdığını anlayabilsem bile benim esas merak ettiğim 9 ve 10 satırlarda write sonucunun neden farklı olduğu ??
E=mc^2
erdem (Moderatör) #2
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
int[] a = [ 3, 5, 7, 8 ];
assert(remove(a, 1) == [ 3, 7, 8 ]);
assert(a == [ 3, 7, 8, 8 ]);

Bunun nedeni aslında remove asıl dizinin boyunu değiştirmiyor. Bunun yerine kırpılmış diziyi döndürüyor.

Buradaki örnekte birinci elemanı kapatalım. O zaman 3, 7, 8 dönecek.  Kalan elemanlar da oluşan boşluğu doldurulacak şekilde bu örnekte 8 kaydırılıyormuş.

Bunun nedeni de std.algorithm in sadece içeriği değiştirecek şekilde [yapıyı değil] tasarlanmış olması imiş.

Kısacası senin örneğinde şu şekilde kullanmak gerekiyor:
import std.stdio;
import std.algorithm;
 
void main(string[] argv)
{
    int[5] dizibes=[8,2,0,7,5];
    int[5] dizialti=[9,3,6,1,4];
    int[] dizitoplam=dizibes~dizialti;
    writeln("ikisini topladım ve sıraladım.....",sort(dizitoplam));
    dizitoplam = dizitoplam.remove(5);
    writeln("5.elemanı çıkarttım ve yazdırdım..",dizitoplam);
    writeln("Tekrar yazdırdım..................",dizitoplam);
}
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Burada başka bir etken daha var: Sabit uzunluklu dizilerin uzunluğu değiştirilemez. Yani, int[5] her zaman için beş elemana sahip olacaktır.

Sabit uzunluklu dizilerle dilimlerin bellekteki durumları da çok farklı: Yukarıdaki sabit uzunluklu dizi, yan yana duran beş elemandan başka bir şey değil. Hatta, program yığıtında duruyor.

dizibes'i gösteren bir dilim ise bellekte şu yapının eşdeğeridir:
    int[] dilim = dizibes;
 
/* 'dilim' iki üyeye sahiptir:
        size_t length; // Doğal olarak değeri 5'tir
        int* ptr;      // dizibes'in ilk elemanını gösteren göstergedir
*/

Ali
cos00kun #4
Üye Kas 2014 tarihinden beri · 104 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Bu durumda dizitoplam.remove(5)); ifadesi bir sonuç veriyor ama atama yapmayınca dizitoplam değişkeninden farklı netice çıkartıyor.. Bana elbetteki benden kaynaklanan sebeplerden dolayı çok saçma geliyor bu tam kavrayamıyorum.. Yine dediğim gibi ben aslında sizi anladığımı sanıyorum bahsettiğiniz kısımlardaki kaydırma ve dizi boyutunun değişmediğini de kavradığımı sanıyorum sadece sorunum şu write işlevinde yazan kısımlardaki aynı sonucu üretememe!!.. sonuç itibariyle benim mantığımda "dizitoplam.remove(5)); ifadesi bir sonuç doğurduğunda bu sonucu write ile yazdığımız vakit ile bir yerlere atadığımızda yazırdığımızla aynı olması lazım.. yada yukarda dediğim gibi ve sizinde anlatmak istediğiniz gibi aslında "dizitoplam.remove(5))" ifadesiyle, "dizitoplkam=dizitoplam.remove(5))" ifadesi aynı sonuçu üretmiyor.. Birazdaha kafa yorayım bakalım belki beynimi ikna ederim :)

Konuyla ilgili sizler kadar deneyimli olmamam sebebiyle sorularımdaki hatalar ve sizlerin uğraşılarınız için anlayışınıza sığınıyorum..
sevgiler saygılar..
E=mc^2
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Öncelikle, sabit uzunluklu dizilerle ilgili söylediklerim bu konuyla ilgili değilmiş çünkü remove() yapılan dizi sabit uzunluklu değil.

Konuyla ilgili sizler kadar deneyimli olmamam sebebiyle sorularımdaki hatalar ve sizlerin uğraşılarınız için anlayışınıza sığınıyorum..

Dizi konuları D'de karışık olabiliyor çünkü sabit-dizilerle dilimler farklı hem de olayın içine aralık kavramı da giriyor. Seninle ilgisi yok. :)

cos00kun:
Bu durumda dizitoplam.remove(5)); ifadesi bir sonuç veriyor ama atama yapmayınca dizitoplam değişkeninden farklı netice çıkartıyor..

Evet. Bunun nedeni, std.algorithm.remove işlevinin bir aralık algoritması olması ve dizi olmayan topluluklarla da işleyebilmesidir. Diziden daha genel türlerle de işleyebildiğinden, eleman çıkartma işlemini, elemanları yer değiştirerek halleder. (Aynı gariplik C++'ın erişicilerle işleyen algoritmalarında da bulunur.)

Sabit uzunluklu dizi kullanıldığında gözlemler şaşırtıcı olabiliyor.

aynı olması lazım

Sonucu aynı değişkene atayınca sorun kalmıyor:
    dizitoplam = dizitoplam.remove(5);
Ali
cos00kun #6
Üye Kas 2014 tarihinden beri · 104 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Bu durumda Dilim ve Aralık kavramlarını birkez daha daha dikkatli okumak gerekiyor sanırım..
E=mc^2
cos00kun #7
Üye Kas 2014 tarihinden beri · 104 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Ali ve Erdem bey tekrar merahabalar.. Dediklerinizi iyice okuyup bu seferde Visual Studionun memory watch seçeneğinden faydalanarak satır satır kodları işletip dizitoplam değişkenini inceledim.. Yine şaşırtıcı şeyler oldu açıkçası..
şimdi size satır satır yazayım,,
breakpoint koyduktan sonra 8.satırın işletimi bitti ve ben ordan aldığım memory resminde(kuvvetle muhtemel stack bölgesinde);
Name- Value
0-0
1-1
2-2
3-3
4-4
5-5
6-6
7-7
8-8
9-9
duruyor.. zaten konsoldada
ikisini topladım ve sıraladım.....[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
gözüküyor sorun yok bu beklediğimiz sonuç.. ardından 9. satırı işlettikten sonra bu stack alanındaki dizitoplam değişkeninin durumu;

Name- Value
0-0
1-1
2-2
3-3
4-4
5-6
6-7
7-8
8-9
9-9
yani aslında burda write ile yazdırdığımızda benimde beklediğim sonuç !! yani stackte de böyle.. oysa write ile yazdırdığımızda
 
5.elemanı çıkarttım ve yazdırdım..[0, 1, 2, 3, 4, 6, 7, 8, 9]
çıkıyor işte sorun burda başlıyor stack ayrı telden çalıyor write ile yazım ayrı :)

ve son olarak  10. satırı işletip stacke bağtığımızda;

Name- Value
0-0
1-1
2-2
3-3
4-4
5-6
6-7
7-8
8-9
9-9
yine yukarıdakiyle aynı ama u sefer write ile dizitoplamı yazdırdığımızda
Tekrar yazdırdım..................[0, 1, 2, 3, 4, 6, 7, 8, 9, 9]

buda beklediğimiz sonuç.. ama kafa karıştırıcı sonuç
E=mc^2
Bu mesaj cos00kun tarafından değiştirildi; zaman: 2017-11-15, 04:38.
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
İki kavramı hatırlayalım:

  • Dizi: Yan yana duran (ve indeksle hızlıca erişilebilen) elemanlar topluluğu. Başka bir şey değil; örneğin, olayın içinde bunların ilkini gösteren gösterge ve hatta kaç adet oldukları bile yok.

Not: Evet, sabit uzunluklu dizilerin bile uzunlukları yok; çünkü uzunluk türlerinin parçası. Yani, uzunlukları derleme zamanında bilinen bir kavram ve çalışma zamanında değişmiyor.

  • Dilim: Yan yana duran elemanlara erişim sağlayan yapı; elemanların ilkini gösteren göstergeden ve eleman adedinden oluşuyor

Çoğu aralık algoritması gibi, remove() da çok kullanışlı olmak isteyen bir işlev. Bu yüzden, yalnızca dizilerle değil, kendisini BidirectionalRange olarak sunabilen her tür aralıkla kullanılabiliyor. BidirectionalRange hem başından hem de sonundan erişim sağlayan aralık demek. (Ek olarak, save() işlevi ile erişme durumunu da saklayabiliyor; yani, "save ettiğim yerden devam edeyim" diyebiliyor.)

remove() şöyle işliyor:

1) Baştan başlayayım

2) Bildirilen indekse gelince durayım

3) O indeksteki elemanı çıkartmış olmak için sonuncu elemanı onun üstüne kopyalayayım indekse yerleştireyim (Aslında bu davranışı değiştirebiliyoruz; aşağıda açıklıyorum)

4) Bir eleman eksilmiş olsun diye (ve tabii o sonuncu eleman iki kere tekrarlanmasın diye) sonuç olarak döndüreceğim aralığı son taraftan bir azaltayım

Yani, silme işlemi asıl elemanların dizi olduklarını bilmeden ve elemanları bir yerden başka yere taşıyarak gerçekleştiriliyor. Dolayısıyla, asıl elemanlar bu örnekteki gibi dizi olduklarında asıl dizide tekrarlanan elemanlar oluyor. (Bu örnekteki sondaki 9 gibi.)

Anlattığım algotirmanın bu örneğe uymadığının farkındayım çünkü ben eleman değiştirme kararınını daha kolay anlatayım diye SwapStrategy.unstable olarak düşündüm. Oysa, varsayılan karar SwapStrategy.stable'dır. stable, elemanların sıralarının korunması, unstable ise korunmaması anlamına gelir.

unstable daha hızlı tek kopyalama yetiyor: 3 numaralı adımda sondaki elemanı belirtilen indekse kopyaladık ve işimiz bitti. stable olsaydı, belirtilen indeksten sonraki bütün elemanları teker teker bir sola kaydırmak gerekirdi. Çok daha fazla eleman kopyalardık ama sonuçta eleman sıralarını korumuş olurduk. Programcı ne istediğine karar verebiliyor. Aynı programı bir de unstable ile çalıştıralım:
    writeln("5.elemanı çıkarttım ve yazdırdım..",dizitoplam.remove!(SwapStrategy.unstable)(5));
Bu sefer sondaki elemanın (yani, 9'un) belittiğimiz indekse gittiğini görüyoruz:

5.elemanı çıkarttım ve yazdırdım..[0, 1, 2, 3, 4, 9, 6, 7, 8]
Tekrar yazdırdım..................[0, 1, 2, 3, 4, 9, 6, 7, 8, 9]


Ali
cos00kun #9
Üye Kas 2014 tarihinden beri · 104 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Çok açıklayıcı oldu sağolun.. Benim kafamı karıştıran kısım D dilinde dilimler, bazı işlevler yada bazı niteliklerin aslında referans gibi çalışabileceğini ve davranabileceği konusunu idrak edememdi sanırım.. Yine konumuza dönersek burada temel nokta şu dizitoplam.remove(5)) aslında eşit değildir dizitoplam=(dizitoplam.remove(5) in sonucuna çıkıyor Write işlevine sokunca 
Yinede
writeln(dizitoplam.remove(5)) ile  writeln(dizitoplam=writeln(dizitoplam.remove(5)) eşit sonuç üretseydi hiç fena olmayacaktı :)
E=mc^2
acehreli (Moderatör) #10
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
(Önemli bir konunun altını çizmeyi unuttuk: remove(5) deyince indeksi 5 olan eleman gider, değeri 5 olan değil.)

cos00kun:
dizitoplam.remove(5)) aslında eşit değildir dizitoplam=(dizitoplam.remove(5)

Bir yerde hata yapıyor olabilirsin çünkü şunlar aynı sonucu üretiyor:
    writeln("5.elemanı çıkarttım ve yazdırdım..",dizitoplam.remove(5));
    writeln("5.elemanı çıkarttım ve yazdırdım..",dizitoplam = dizitoplam.remove(5));
Ama ikisini aynı programda öyle art arda çağırırsan remove(5) iki kere çağrıldığından kafa karıştırıcı olabiliyor. (Hatırlarsan birinci satır 'dizitoplam'ın hangi elemanları gösterdiğini değiştirmiyor.)

Ali
cos00kun #11
Üye Kas 2014 tarihinden beri · 104 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
off offf  ;-) aslında benim için iyi bir beyin jimnastiği sizin içinde sanırım biraz eziyet oldu ama sonunda soru işaretsiz olarak konuyu anladığımı sanıyorum.. bu topic boyunca anlayamadığım ve şimdi tam olarak anladığım sanırım şu dizitoplamın elemansayısı 10 olduğundan yığıtta 10 adet elemanı göstermesi oysa remove yi direk write da kullanınca haklı olarak dizitoplamdan 1 eksik eleman yazdırması.. tam doğru ifade edebildimmi bilemiyorum ama en azından çelişen hiç bir durum kalmadı kafamda ... tekrar sağolun Ali ve Erdem hocam...
E=mc^2
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-19, 20:03:11 (UTC -08:00)