Forum: Projeler KelimeMatik RSS
Soru sayısına göre liste hazırlamak
zafer #1
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Soru sayısına göre liste hazırlamak
    private void KelimeListesiHazirla()
    {
        string s = cast(string)std.file.read(_kelimeDosyasi); 
    
        // XML formatını kontrol et
        check(s); 
    
        int soruSay = 0;
        
        DocumentParser xml = new DocumentParser(s); 
        xml.onStartTag["kelime"] = (ElementParser xml) 
        { 
            Kelime kelime;
            kelime.seviye = to!Seviye(xml.tag.attr["seviye"]); 
        
            xml.onEndTag["soru"] = (in Element e) { kelime.soru = e.text; }; 
            
            xml.onStartTag["cevaplar"] = (ElementParser xml)
            {
                xml.onEndTag["cevap"] = (in Element e) { kelime.cevaplar ~= e.text; }; 
                xml.parse();
            };
            
            xml.onStartTag["zit-anlamlilar"] = (ElementParser xml)
            {
                xml.onEndTag["zit-anlam"] = (in Element e) { kelime.zitAnlamlar ~= e.text; }; 
                xml.parse();
            };
        
            xml.parse(); 
        
            _kelimeListesi ~= kelime;
            ++soruSay;
            
            writefln("soruSayisi: %s, soruSay: %s", _soruSayisi, soruSay);    
        
            // XML dosyasından istenen soru adedi alınmışsa işlemi bitir
            if (soruSay == _soruSayisi)
            {
                return;
            }
        }; 
        
        xml.parse(); 
    }

Yukarıdaki metod egzersiz için soru hazırlıyor. Ancak bu metod kendisine verilen XML dosyasının tamamını okuyordu. Ben ise dosyadan istediğim sayıda soru okuyup geri kalanlar için işlem yapmasını istemiyorum. Bunun için okunan soru sayısı ile istenen soru sayısını karşılaştırıp ikisi eşitlendiğinde işlemi sonlandırmayı denedim ama başarılı olmadım. Sanırım benim return işlemimin sadece temsilcinin gösterdiği metodun dışına çıkıyor ama aslında hala aynı metod içinde kalıyorum?
https://github.com/zafer06 - depo
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4511 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
zafer:
    private void KelimeListesiHazirla()
    {
// ...
        DocumentParser xml = new DocumentParser(s); 
        xml.onStartTag["kelime"] = (ElementParser xml) 
        {
// ...
            if (soruSay == _soruSayisi)
            {
                return;
            }
        };
        
        xml.parse(); 
    }

Bunun için okunan soru sayısı ile istenen soru sayısını karşılaştırıp ikisi eşitlendiğinde işlemi sonlandırmayı denedim ama başarılı olmadım. Sanırım benim return işlemimin sadece temsilcinin gösterdiği metodun dışına çıkıyor ama aslında hala aynı metod içinde kalıyorum?

Evet, oradaki return yalnızca "kelime" elemanının işlemini sonlandırıyor. Zaten en sondaki işlem olduğu için de o delegate'ten return olmadan çıkmakla aynı anlama geliyor.

std.xml'in belgelerinde "bütün işlemi sonlandır" gibi bir olanak göremiyorum. Hatta şöyle diyorlar:

std_xml.html:
Parsing will continue until the end of the current element.

Yani bu elemanın sonuna kadar okuyacaklar. Ama bu eleman en dışarıdaki eleman olduğuna göre herşey okunacak demektir. Bence bu kütüphanede başka yolu yok.

(Aslında işlemler sırasında hata atarak olayı yarıda kesebiliriz ama bu hata atma düzeneğinin nerelerde kullanılmamasının bir örneğidir. Programın normal işleyişini etkilemek için hata atılmaz; hatalı durumlarda atılır.)

Bu güne kadar bütün XML dosyalarını biz de hep sonuna kadar okumuştuk.

Aslında biraz düşününce öyle olmasının doğru olduğunu görüyorum. XML dosyasının herhangi düzeyinde de durdurabilmeli miyiz? Öyle yaparsak okunan verinin doğruluğu hakkında ne söyleyebiliriz? Bir sonra gelecek olan alt eleman belki de önemlidir.

Öte yandan bütün dosyayı okumakta hiç sorun da olmayabilir. İlgilenenlere program fikri: içinde çok sayıda "kelime" elemanı bulunan bir XML dosyası oluşturun. (Bunu tabii ki bir D programı ile yapın. ;)) Sonra bunları KelimeListesiHazirla() işlevi ile işleyerek ne kadar zaman geçtiğine bakın.

Ben ise dosyadan istediğim sayıda soru okuyup geri kalanlar için işlem yapmasını istemiyorum.

O zaman kelimeler zaten hep aynı sırada gelirler (veya hep aynı kelime kümesinden kullanılmış olurlar). Hepsini okuyup karıştırıp sonra belirli adedini kullanmak daha kullanışlı olabilir.

Ali
zafer #3
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
(Aslında işlemler sırasında hata atarak olayı yarıda kesebiliriz ama bu hata atma düzeneğinin nerelerde kullanılmamasının bir örneğidir. Programın normal işleyişini etkilemek için hata atılmaz; hatalı durumlarda atılır.)

Bu fikir benimde aklıma geldi ama seninde belirttiğin sebeple kullanmaktan vazgeçtim.

Bu güne kadar bütün XML dosyalarını biz de hep sonuna kadar okumuştuk.

Aslında biraz düşününce öyle olmasının doğru olduğunu görüyorum. XML dosyasının herhangi düzeyinde de durdurabilmeli miyiz? Öyle yaparsak okunan verinin doğruluğu hakkında ne söyleyebiliriz? Bir sonra gelecek olan alt eleman belki de önemlidir.

Doğrusu bende çalıştığım programlarda hep böyle yapıyorum yani dosya sonuna kadar okuyorum ama bizim durumda bu xml dosyası aynı zamanda sistemin veri tabanı gibi davrandiği için örneğin 5_000 kelime içeren bir dosyanın tamamını okumak yerine belki işimize yarar bir kısmını okumak daha güzel olur diye düşünmüştüm ama sanırım şimdilik tamamını okumak daha iyi olacak belki ileride gerekirse başka bir şeyler düşünürüz.

Öte yandan bütün dosyayı okumakta hiç sorun da olmayabilir. İlgilenenlere program fikri: içinde çok sayıda "kelime" elemanı bulunan bir XML dosyası oluşturun. (Bunu tabii ki bir D programı ile yapın. ;)) Sonra bunları KelimeListesiHazirla() işlevi ile işleyerek ne kadar zaman geçtiğine bakın.

Program fikri hoşuma gittiği ve ileride XML dosyası ile çalışmalar yapacağım için hazırlık olması açısından bir şeyler kodlamaya çalıştım. Ancak göründüğü kadar kolay değilmiş uğraşılarım sonucu dosyaya yazma işlemini bitirebildim. Aslında takıldığım nokta dosyadaki elemanın en sonuna yeni bir eleman ekleyememek. Yani yeni bir eleman eklediğimde bunu gidip dosyanın en altına ekliyor yani kapanmış olan </kelimeler> etiketinin altına böyle oluncada iş bozuluyor tabi. Yani dosya sonuna yeni eleman ekleyemiyorum.


Aslında şu adreste https://github.com/tomeksowi/phobos/blob/master/std/xml.d#… yeni geliştirilen bir XMLWriter sınıfı buldum bir çıkış aralığı ile çalışıyor (OutputRange) ama daha sonra bu geliştirmenin orjinal kütüphanede bulunmadığını farkettim ve vazgeçtim.

Neticede her defasında tüm dosyayı okuyup, eklenecekleri ekleyip dosyayı yeniden yazıyorum ama bu da oldukça yavaşlıyor. Örneğin 1_000 kayıt için denediğimde 950'den sonra artık iyice yavaşlamıştı :) Gerçi biz sadece okuma yapacağız tahminim hızdan dolayı bir sorun olmaz. Yeni eleman ekleme konusunda senin bir bilgin var mı Ali, dosya sonuna yeni eleman ekleme şansımız olursa hem hızın hemde işlerimizin daha kolaylaşacağını düşünüyorum?

Uğraştığım kodlar aşağıda ; Programın çalışması için içeriği boş bir data.xml dosyası çalışma dizininde olmalı.

import std.xml;
import std.stdio;
import std.string;
import std.conv;
import std.random;
 
enum Seviye { temel, orta, ileri }
 
struct Kelime
{
    Seviye seviye;
    string soru;
    string[] cevaplar;
    string[] zitAnlamlar;
}
 
void main()
{
    Kelime[] kelimeler;
        
    for (int i = 0; i < 100; ++i)
    {
        kelimeler ~= XmlDosyasiniOku();
        kelimeler ~= VerYeniBirKelime();
    
        DosyayaKelimeEkle(kelimeler);
        
        writefln("Eklenen Kelime No : %s", to!string(i));
    }
}
 
Kelime VerYeniBirKelime()
{
    //char[] alfabe = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','r','s','t','u','v','y','z'];
    string alfabe = "abcdefghijklmnoprstuvyz";
    
    string soru;
    for (int i = 0; i < uniform(5, 10); ++i)
    {
        soru ~= alfabe[uniform(0, 22)];
    }
    
    string[] cevaplar;
    for (int j = 0; j < 5; ++j)
    {
        string cevap;
        for (int i = 0; i < uniform(5, 10); ++i)
        {
            cevap ~= alfabe[uniform(0, 22)];
        }
        cevaplar ~= cevap;
    }
    
    string[] zitAnlamlar;
    for (int z = 0; z < 5; ++z)
    {
        string zitAnlam;
        for (int i = 0; i < uniform(5, 10); ++i)
        {
            zitAnlam ~= alfabe[uniform(0, 22)];
        }
        zitAnlamlar ~= zitAnlam;
    }
    
    Kelime kelime;
    kelime.seviye = Seviye.temel;
    kelime.soru = soru;
    kelime.cevaplar = cevaplar;
    kelime.zitAnlamlar = zitAnlamlar;
    
    return kelime;
}
 
void DosyayaKelimeEkle(Kelime[] kelimeler)
{
    auto doc = new Document(new Tag("kelimeler"));
    
    foreach(kelime; kelimeler)
    {
        auto birKelime = new Element("kelime");
        birKelime.tag.attr["seviye"] = to!string(kelime.seviye);
 
        auto soru = new Element("soru", kelime.soru);
        
        auto cevaplar = new Element("cevaplar");
        foreach (cevap; kelime.cevaplar)
        {
            cevaplar ~= new Element("cevap", cevap);
        }
        
        auto zitAnlamlar = new Element("zit-anlamlilar");
        foreach (zitAnlam; kelime.zitAnlamlar)
        {
            zitAnlamlar ~= new Element("zit-anlam", zitAnlam);
        }
        
        birKelime ~= soru;
        birKelime ~= cevaplar;
        birKelime ~= zitAnlamlar;
 
        doc ~= birKelime;
    }
    
    File xmlDosya = File("test.xml", "w");
    xmlDosya.writeln("<?xml version=\"1.0\"?>");
    xmlDosya.writefln(join(doc.pretty(3),"\n"));
}
 
Kelime[] XmlDosyasiniOku()
{
    Kelime[] kelimeListesi;
    
    string s = cast(string)std.file.read("data.xml"); 
 
    // XML formatını kontrol et
    //check(s); 
 
    DocumentParser xml = new DocumentParser(s); 
    xml.onStartTag["kelime"] = (ElementParser xml) 
    { 
        Kelime kelime;
        kelime.seviye = to!Seviye(xml.tag.attr["seviye"]); 
    
        xml.onEndTag["soru"] = (in Element e) { kelime.soru = e.text; }; 
        
        xml.onStartTag["cevaplar"] = (ElementParser xml)
        {
            xml.onEndTag["cevap"] = (in Element e) { kelime.cevaplar ~= e.text; }; 
            xml.parse();
        };
        
        xml.onStartTag["zit-anlamlilar"] = (ElementParser xml)
        {
            xml.onEndTag["zit-anlam"] = (in Element e) { kelime.zitAnlamlar ~= e.text; }; 
            xml.parse();
        };
    
        xml.parse(); 
    
        kelimeListesi ~= kelime;
    }; 
    
    xml.parse(); 
    
    return kelimeListesi;
}
https://github.com/zafer06 - depo
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4511 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
zafer:
tamamını okumak yerine belki işimize yarar bir kısmını okumak daha güzel olur

Bu konuya biraz daha bakınca bunun belki de mümkün olduğunu gördüm. Bir de "kelimeler" için onStartTag delegate'i versek ve xml.parse()'ı onun içinden başlatsak, o zaman tarama işleminin geri kalanı hep "kelime" delegate'i içindeki xml.parse() ile devam eder. Denemedim ama şöyle bir şey:

    // yeni delegate
    xml.onStartTag["kelimeler"] = (ElementParser xml) 
    { 
        xml.onStartTag["kelime"] = (ElementParser xml) 
        { 
            // ... eskisi gibi ama artık devam etmediğimizde xml.parse() demeyiz
        }; 
 
        xml.parse();
    }
 
    xml.parse(); // <-- Bu yalnızca "kelimeler"e girmek için. Gerisi içerideki xml.parse()'larla devam eder. 

Dediğim gibi, denemedim ama mantıklı geliyor.

takıldığım nokta dosyadaki elemanın en sonuna yeni bir eleman ekleyememek

En kolayı, bütün dosyayı baştan yazmaktır. Bilgi örneğin Kelime[] olarak bellekte oluşturulur ve sonra bir kere dosyaya yazılır.

XMLWriter sınıfı buldum bir çıkış aralığı ile çalışıyor (OutputRange) ama daha sonra bu geliştirmenin orjinal kütüphanede bulunmadığını farkettim ve vazgeçtim.

std.xml eninde sonunda değişecek. Belki onu kullanırlar.

Neticede her defasında tüm dosyayı okuyup, eklenecekleri ekleyip dosyayı yeniden yazıyorum ama bu da oldukça yavaşlıyor.

Dosya işlemlerini kelime for döngüsünün dışına almak gerek. Yoksa tekrar tekrar açılıp kapatılıyor.

Ben şöyle bir şeyle denedim (kodda bir de data.xml ve test.xml karışıklığı var. Onu da düzelttim tabii):

import std.datetime;
 
// ...
 
void main()
{
    for (int adet = 10; 100_000; adet *= 10) {
        Kelime[] kelimeler;
 
        for (int i = 0; i < adet; ++i)
        {
            kelimeler ~= VerYeniBirKelime();
        }
 
        DosyayaKelimeEkle(kelimeler);
 
        StopWatch kronometre;
        kronometre.start();
        kelimeler = XmlDosyasiniOku();
        kronometre.stop();
 
        writefln("Adet: %s, süre: %s ms",
                 kelimeler.length, kronometre.peek().msecs);
    }
}

Çıktısı şöyle:

Adet: 10, süre: 2 ms
Adet: 100, süre: 10 ms
Adet: 1000, süre: 109 ms
Adet: 10000, süre: 1076 ms
Adet: 100000, süre: 11312 ms


Yüz bin kelime için 11 saniye bile çok fazla. Tarama işlevi ile de biraz ilgilenebiliriz. Örneğin delegate içindeyken tekrar tekrar onStartTag çağrılması bile bana garip geliyor. (Ama onların örneğinde de öyle).

Başka çözümler de bulunur nasıl olsa. Örneğin en azından seviyeler ayrı dosyalarda durabilirler.

Hatta yalnızca senin ihtiyacını karşılayan bir XML modülü yazmaya ne dersin? :)

Ali
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4511 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
xml.onStartTag["kelimeler"] konusunda söylediğimi denedim ama işe yaramadı. Ama aranan çözümü de buldum: if (soruSay == _soruSayisi) denetimini xml.parse()'ın etrafına koymak gerekiyor.

Oynarken kodun biçimi değişti ama şu kod ancak 3 tane kelime okuyor:

    xml.onStartTag["kelime"] = (ElementParser xml) {
        Kelime kelime;
 
        kelime.seviye = to!Seviye(xml.tag.attr["seviye"]);
 
        xml.onEndTag["soru"] = (in Element e) {
            kelime.soru = e.text;
        };
 
        xml.onStartTag["cevaplar"] = (ElementParser xml) {
            xml.onEndTag["cevap"] = (in Element e) {
                kelime.cevaplar ~= e.text;
            };
 
            xml.parse();
        };
 
        xml.onStartTag["zit-anlamlilar"] = (ElementParser xml) {
            xml.onEndTag["zit-anlam"] = (in Element e) {
                kelime.zitAnlamlar ~= e.text;
            };
 
            xml.parse();
        };
 
        xml.onEndTag["kelime"] = (in Element e) {
            kelimeListesi ~= kelime;
        };
 
        if (kelimeListesi.length < 3) {
            xml.parse();
        }
    };

Ama çok yavaş. :-/

Ali
zafer #6
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #4
acehreli:
Dosya işlemlerini kelime for döngüsünün dışına almak gerek. Yoksa tekrar tekrar açılıp kapatılıyor.

Ben şöyle bir şeyle denedim (kodda bir de data.xml ve test.xml karışıklığı var. Onu da düzelttim tabii):

Bende koddaki o yavaşlığa bir anlam verememiştim ama kodlama sürecinden biraz yorulduğum için çok irdelemedim :nuts: . Zaten ne kadar yorulmuş olduğum kodlardan da belli herşey birbirine girmiş  :blush: Senin uyarından sonra bende biraz düzenleme yaptım ve şimdi hızı gözle görülür şekilde düzeldi. Hız için senin testlerinde de görüldüğü gibi çok iyi olmasada bizim için yeterli diye düşünüyorum.

Hatta yalnızca senin ihtiyacını karşılayan bir XML modülü yazmaya ne dersin? :)

Bana sormana gerek yok  ;-) , bana kalsa harika bir fikir hemen başlayalım derim kesinlikle keyifli bir tecrübe olacağını düşünüyorum ama böyle dallandıkça ana projeye vakit kalmıyor. Öncelikle kelimematik'in kullanılabilir bir sürümünü oluşturmak istiyorum. Bu sebeple bu güzel fikri kelimematik yol haritasında şimdilik belirsiz bir tarihi not düşüyorum :-D . Bu arada yol haritası konusunu forumun başına sabitlersek bizi takip edenler ve bizim için daha güzel olur diye düşünüyorum. http://ddili.org/forum/thread/654

XML dosya okuma konusunda senin önerine uyup dosyanın tamamını okumaya karar verdim. Okuma hızının en azından kelimematik gibi bir program için tatminkar olduğu kanısındayım. XML konusundaki işlemleri şimdilik mevcut durumda bırakmaya karar verdim. Şimdilik durum idare eder, ilerisi için farklı geliştirmeler yapabiliriz.
https://github.com/zafer06 - depo
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:
Forum: Projeler KelimeMatik RSS
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-10-21, 03:08:53 (UTC -07:00)