Thread overview
foreach döngüsünde sayaç arızası
Oct 19, 2011
zafer
Oct 20, 2011
zafer
October 20, 2011

Gerçekten projeler ögrenim için kesinlikle şart, bu iş sadece okuyarak olmuyor, olayın içine girip yaşamak gerekiyor. Aşagıdaki kod çalışıyor.

	private void SoruListesiHazirla()
	{
		File dosya = File(_soruDosyasi, "rb");

		foreach (satir; dosya.byLine())
		{
			string[] soru = cast(string[])split(satir, ":");

			//_soruListesi.length = i + 1;
			//_soruListesi[i] = Soru(soru[0], soru[1]);
		}
	}

Ancak aynı kodda foreach döngüsüne i sayaç değişkenini eklediğimde "Segmentation fault" hatası alıyorum. İlgili kod aşağıda,

	private void SoruListesiHazirla()
	{
		File dosya = File(_soruDosyasi, "rb");

		foreach (i, satir; dosya.byLine())
		{
			string[] soru = cast(string[])split(satir, ":");

			//_soruListesi.length = i + 1;
			//_soruListesi[i] = Soru(soru[0], soru[1]);
		}
	}

Sorun ne olabilir?

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 20, 2011

Alıntı (zafer):

>

Gerçekten projeler ögrenim için kesinlikle şart, bu iş sadece okuyarak olmuyor, olayın içine girip yaşamak gerekiyor.

Kesinlikle! Bu kadar çok ve güzel konuyu açtığın için gerçekten çok teşekkürler. Öğreniyoruz ve pekiştiriyoruz.

Alıntı:

>

kodda foreach döngüsüne i sayaç değişkenini eklediğimde "Segmentation fault" hatası alıyorum. İlgili kod aşağıda,

> 	private void SoruListesiHazirla()
> 	{
> 		File dosya = File(_soruDosyasi, "rb");
>
> 		foreach (i, satir; dosya.byLine())
> 		{
> 			string[] soru = cast(string[])split(satir, ":");
>
> 			//_soruListesi.length = i + 1;
> 			//_soruListesi[i] = Soru(soru[0], soru[1]);
> 		}
> 	}
> ```

>
> Sorun ne olabilir?
>

Aynısını dün ben de yaşamış ve konuyu uzatmamak için yazmamıştım. ;)

Bu sayaç konusu İngilizce forumlarda da tartışılmıştı. Derleyicinin bu desteği her tür için otomatik olarak vermesinin iyi olacağı savunulmuştu. Ne yazık ki çeşitli nedenlerle olmadı.

Burada foreach ile kullanılan tür, std.stdio.File.ByLine (byLine() işlevi tembel bir ByLine döndürür.) Bir tür olan ByLine, foreach ile nasıl işleyeceğini kendisi belirlediği için, sayaç sunup sunmayacağı ona kalmış oluyor.

Kısa yanıt: ByLine'ın belgeleri sayaç kullanımı göstermediği için onu sayaçla kullanamıyoruz.

Uzun yanıt: ByLine'ın tanımına baktığımda foreach desteğini opApply() ile değil; empty(), front(), ve popFront() aralık işlevleri ile sağladığını görüyorum. Zaten aralık işlevleri kullanıldığında foreach için yükleme sağlanamıyor. Tek yapabildiğimiz, foreach'te tek değişken kullanmak.

Bütün bunlara bakınca, aslında foreach'in bu durumda iki değişkenle kullanılmasının yasal olmaması gerektiğini görüyorum. Derleyici izin vermemeliydi.

Evet, bilinen bir hataymış:

 http://d.puremagic.com/issues/show_bug.cgi?id=6723

dmd'nin git'teki son halinde de galiba çözülmüş:

 https://github.com/D-Programming-Language/dmd/commit/569077b

Kısacası, lütfen bir sonraki sürümü bekleyiniz. :)

Keşke daha hoş olabilseydi ama en basit çözüm, kendi sayaç'ımızı tanımlamak:


int sayaç;
foreach (satır; dosya.byLine()) {
writefln("%s: %s", sayaç, satır);
++sayaç;
}



Şimdi, her ne kadar son derece okunaksız olsa da bu işin aralıklarla da yapılabileceğini göstermek istiyorum:


import std.stdio;
import std.range;

void main()
{
auto dosya = File("deneme.txt");

foreach (sayaç_ve_satır; zip(iota(int.max), dosya.byLine())) {
writefln("%s: %s", sayaç_ve_satır[0], sayaç_ve_satır[1]);
}
}



iota, kendisine verilen değere kadar teker teker sayar. zip ise kendisine verilen belirsiz sayıdaki aralığı aynı miktarda adım adım ilerletir. Sonuçta iota sayar, ByLine satır satır ilerler.

zip'in değeri, kendisine verilen aralıkların elemanlarından oluşan bir çokuzludur (tuple). O çokuzlu değerin 0 numaralı elemanı iota'ya, 1 numaralı elemanı da ByLine'a karşılık geliyor.

Çokuzlular bölümü:

 http://ddili.org/ders/d/cokuzlular.html

Tabii bence yukarıdaki zip'li çözüm oldukça okunaksız. Acaba iota'nın görevini kendi içine gizleyen bir aralık tanımlasak nasıl olur:


import std.stdio;
import std.range;

/*

  • Bu aralık herhangi bir InputRange aralığı ile işleyebilir. Bu aralığın

  • elemanları, aşağıdaki Sayaçla.Eleman türünden oluşurlar.
    */
    struct Sayaçla(Aralık)
    if (isInputRange!Aralık)
    {
    size_t sayaç;
    Aralık aralık; // asıl aralık
    Eleman baştaki; // front()'tan döndüreceğimiz elemanımız

    // Bu aralığın elemanları iki parçadan oluşur
    struct Eleman
    {
    size_t sayaç;
    ElementType!Aralık eleman;
    }

    // Aralık boş kabul edildiğinde varsayılan bir Eleman döndürüyoruz (zaten
    // kullanıcılar aralığımız boş olduğunda bizi çağırmamalıdırlar); yoksa
    // geçerli bir sayaçtan ve asıl elemandan oluşturuyoruz.
    void baştakiniKur()
    {
    baştaki = (empty
    ? Eleman()
    : Eleman(sayaç, aralık.front()));
    }

    this(Aralık aralık)
    {
    this.sayaç = 0;
    this.aralık = aralık;

     baştakiniKur();
    

    }

    @property bool empty() const
    {
    return aralık.empty;
    }

    Eleman front()
    {
    return baştaki;
    }

    void popFront()
    {
    ++sayaç;
    aralık.popFront();
    baştakiniKur();
    }
    }

// Hemen hemen bütün yapı ve sınıf şablonunda olduğu gibi bir kolaylık işlevi
Sayaçla!Aralık sayaçla(Aralık)(Aralık aralık)
{
return Sayaçla!Aralık(aralık);
}

void main()
{
auto dosya = File("deneme.txt");

foreach (i; sayaçla(dosya.byLine())) {
writefln("%s: %s", i.sayaç, i.eleman);
}
}



Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
October 21, 2011

Alıntı:

>

Kesinlikle! Bu kadar çok ve güzel konuyu açtığın için gerçekten çok teşekkürler. Öğreniyoruz ve pekiştiriyoruz

Bu yazıları değerli kılan benim yazdığım sorular değil senin verdiğin detaylı ve açıklayıcı cevaplar Ali. Bu sebeple burada teşekkür edilecek tek kişi görüyorum, o da sensin. Bu yazıları okuyanların sana bir teşekkür borcu var gibi geliyor bana ;-)

Alıntı:

>

Aynısını dün ben de yaşamış ve konuyu uzatmamak için yazmamıştım. ;)

Ne diyebilirim bilemiyorum. Dün saatlerce aradım, dersaneden foreach konusunu tekrar tekrar okudum, yarım yamalak ingilizcemle haber gruplarını araştırdım, daha sonra şurada (http://ddili.org/forum/thread/628) konuştuğumuz konu aklıma geldi onu inceledim. Doğrusunu söylemek gerekirse oldukça çok uğraştım keşke önceki yazında sayaç arızası durumunu not olarak ekleseydin.
Neyse gerçi bu sayde bende foreach'i bayağı yakından tanımış oldum :)

Alıntı:

>

Burada foreach ile kullanılan tür, std.stdio.File.ByLine (byLine() işlevi tembel bir ByLine döndürür.) Bir tür olan ByLine, foreach ile nasıl işleyeceğini kendisi belirlediği için, sayaç sunup sunmayacağı ona kalmış oluyor.

Doğrusu ben sayaç kavramının foreach döngüsüne ait olduğunu düşünüyordum. Yani her çevrim için otomatik olarak artan bir değer gibi düşünmüştüm. Sayacın topluluğa ait olması değişik tabi, sanırım bununda kendine göre bazı avantajları ve bu durumdaki gibi dezavantajları var. Yinede bunu öğrendiğim çok iyi oldu. Bence dersane bölümündede bu konu özellikle belirtilmeli.

Alıntı:

>

Kısacası, lütfen bir sonraki sürümü bekleyiniz. :)

Bekleriz sıkıntı yok :) Bence şu zamanlar D'nin en güzel zamanları o sebeple böyle ufak aksilikler D'nin keyfini çıkarmama engel olamaz :)

Bu arada yazdığın kodlar için teşkkürler, emek ve zaman harcayıp güzel şeyler çıkarmışsın ama şu aralıklar konusuna hala giriş yapamadım. Ayrıca doğrusunu söylemek gerekirse basit bir sayaç değişkeni tanımlayıp kullanmak çok daha pratik ve kolay göründü bir an gözüme :-D

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

October 21, 2011

Alıntı (zafer):

>

keşke önceki yazında sayaç arızası durumunu not olarak ekleseydin.

Tamam. Tembel hisleri bastırmaya çalışacağım. :)

Alıntı:

>

Doğrusu ben sayaç kavramının foreach döngüsüne ait olduğunu düşünüyordum. Yani her çevrim için otomatik olarak artan bir değer gibi düşünmüştüm.

Senin gibi düşünen çok insan var. :)

Alıntı:

>

sanırım bununda kendine göre bazı avantajları ve bu durumdaki gibi dezavantajları var

Eminim. Genellikle bu tartışmaların sonunda "şu öteki durumla çelişirdi" gibi bir açıklama geliyor.

Hemen aklıma gelen bir örnek: Noktalardan oluşan türümüzün foreach döngüsü iki biçimde kullanılabilsin. Tek değişkenle kullanıldığında x değeri, iki değişkenle kullanıldığınd x ve y değerlerini elde etsek.

foreach (x; noktalar)       // <-- tek değişken olduğu için x olduğu belli
// ...
foreach(sayaç, x; noktalar) // <-- derleyici otomatik sayaç değeri mi versin;
                           //     yoksa bizim x ve y döndüren olanağımız mı
                           //     kullanılsın ve x değeri sayaç değişkeninde
                           //     ve y değeri de x değişkeninde mi gelsin?

Alıntı:

>

. Yinede bunu öğrendiğim çok iyi oldu. Bence dersane bölümündede bu konu özellikle belirtilmeli.

Teşekkürler; not aldım.

Alıntı:

>

basit bir sayaç değişkeni tanımlayıp kullanmak çok daha pratik ve kolay göründü bir an gözüme :-D

Bence de. :) Ben yalnızca farklı bir bakış açısı olarak gösterdim. Yoksa kodun okunaklılığı çok önemli. C++ kullanırken de erişicilerin ve algoritmaların karmaşık kullanımları yerine basit olanları yeğliyorum.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]