Forum: D Programlama Dili RSS
D ile "Hacim ağırlık ortalama fiyat"  hesaplaması
kerdemdemir #1
Üye Eyl 2013 tarihinden beri · 53 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: D ile "Hacim ağırlık ortalama fiyat"  hesaplaması
Selam Arkadaşlar ,

İş amaçlı D dilini kullanma fırsatı buldum. Ali Hocamızınki gibi güzel olmadı tabi,  ben dahil olmak üzere kod çok beğenilmedi.

 "Hacim ağırlık ortalama fiyat(vwap diyolar)"  diye bir şey varmış arkadaşlar örnekle anlatacak olursam diyelimki bir elma 5 lira ve ben bu elmadan 20 tane aldım sonra aynı gün bu elmadan 10 tane fakat bu sefer 8 liraya aldım. Burumda bu "vwap" dediğimiz şey 5*20 + 8*10 / 30 = 6, 6 olarak hesaplanıyor.

 Elimizdeki data ".csv" formatında ve şuna benziyor ama bir sürü satır var

2013-12-16;DE0009652388;FESX;FUT ON EURO STOXX 50;EUREX;EUR;;EU0009658145;F;2013-12;2013-12-20;0.00;0.00;0;0;N;;11:26:26.220000;0;XX;2957.00;2;N
2013-12-16;DE0009652388;FESX;FUT ON EURO STOXX 50;EUREX;EUR;;EU0009658145;F;2013-13;2013-12-20;0.00;0.00;0;0;N;;10:56:24.580000;0;XX;2943.00;10;N
2013-12-16;DE0009652388;FESX;FUT ON EURO STOXX 50;EUREX;EUR;;EU0009658145;F;2013-14;2013-12-20;0.00;0.00;0;0;N;;17:25:00.410000;0;XX;2972.00;1;N


Miktar 21.(sondan 1.) sıradaki sırayla 2,10 ve 1 olan alanlar.
Fiyat 20. sıradaki alanlar sırayla 2957, 2943 ve 2972.

Bu değeri değişik günler için hesaplamız gerekiyor ve tarihte 10. sıradaki 2013-12-20 değerindeki alan. Benim gönderdiğim örnekte sadece 3 satır ve 1 tane tarih var fakat benim parse etmem beklenen dosyada değişik tarihler vardı yüzbinlerce satır vardı.


Ben bu isteği D ile şöyle gerçekleştirmeye çalıştım.

 
import std.stdio;
import std.getopt;
import std.string;
import std.range;
import std.typecons;
import std.conv;
import std.algorithm;
import std.file;
 
string data = "5202-dod_FESX_20131216.csv";
alias totalCostAmountPair = Tuple!(double, int);
 
totalCostAmountPair[ dstring ] totalCostAndAmountForEachDate;
 
int main(string[] argv)
{
    auto helpInformation = getopt( argv,  "file",    &data);
 
    if (helpInformation.helpWanted)
    {
        defaultGetoptPrinter(" Only valid input is the fileName ",
                             helpInformation.options);
        return 0;
    }
    if ( !exists(data) || !isFile(data) )
    {
        writeln( "Please make sure the file exists" );
        return 0;
    }
 
    auto file = File(data, "r");
 
 
 
    auto dateAmountPriceTupleList =                file.byLine().
                                                map!(a => to!dstring(a).split(";")).
                                                map!(a => a.indexed([10,20,21])).array();
                                                
 
    foreach ( dataTriple ; dateAmountPriceTupleList )
    {
        auto cost = to!double(dataTriple[1]);
        auto amount = to!int(dataTriple[2]);
        auto curValPtr = dataTriple[0] in totalCostAndAmountForEachDate;
        if (  curValPtr !is null )
        {
            auto curVal = *curValPtr;
            totalCostAndAmountForEachDate[dataTriple[0]] =     tuple(curVal[0] + cost * amount, curVal[1] + amount);
        }
        else 
            totalCostAndAmountForEachDate[dataTriple[0]] = tuple(cost * amount, amount);
        
    }
 
    foreach ( key ; totalCostAndAmountForEachDate.keys )
    {
        totalCostAndAmountForEachDate[key][0] /= totalCostAndAmountForEachDate[key][1];
        writeln( "VWAP for date: ", key, " is " , totalCostAndAmountForEachDate[key][0] );
    }
 
    return 0;
}

Kodum çalıştı ama rangeleri birazda zaman kısıtılaması olduğundan istediğim kadar kullanamadım.
Sizin düşünceleriniz varmıdır?

Sevgiler
Bu mesaj 2 defa değişti; son değiştiren: kerdemdemir; zaman: 2016-07-14, 05:39.
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4391 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
  • İçinde virgül olmayan dosyaya .csv isminin verilmesini garip karşılamak üzereydim ama Türkiye gibi virgülün kesirli sayılarda geçtiği ülkelerde normal olduğunu öğrendim. :)

  • totalCostAndAmountForEachDate'i daha yerel bir kapsamda tanımlamak daha iyi

  • Bunun gibi tek dosyadan okuyan programların giriş ve çıkışlarının birbirlerine bağlanması yaygındır. Eğer şöyle kullanabilsen, dosya ismiyle ilgilenmen gerekmez ve programın kendisini stdin'den okuyacak biçimde yazabilirsin:

programim < 5202-dod_FESX_20131216.csv

  • Bu programda dstring'e gerek görünmüyor. (Hatırlatmak için: harfleri dizgi[42] diye doğrudan indeksleme ihtiyacımız yoksa doğrudan string kullanabiliriz.)

  • .array()'i çağırmaya gerek yok çünkü satırlara indeksle erişmeye gerek yok. Yaptığımız tek şey, dosyayı baştan sona taramak ve sonuçta bir eşleme tablosu oluşturmak. Buradaki .array() çağrısı aralıkların zincirlenebilmelerinin en önemli yararlarından birisini etkisiz kılmış oluyor.

  • Hatırlatma amacıyla, elemanın eşleme tablosunda olup olmadığına bakmaya genelde gerek yok:
void main() {
    int[int] a;
    ++a[42];    // olmayan elemanı ekler ve arttırır
 
    assert(a == [ 42 : 1 ]);
}
Ancak, o basitlik kullanıcı türlerinde bulunmuyor. Ek olarak, sanırım burada double'ın ilk değeri .nan olduğu için if (  curValPtr !is null ) diye denetlemek gerekmişti. Onun önüne geçmek için bir struct kullanabiliriz ve double üyesinin ilk değerini 0 olarak belirleyebiliriz.

  • amount sözcüğünün adet anlamına geldiği açık değil. Ona quantity demek daha doğru.

  • foreach gibi döngü deyimleri yerine aralık işlevleri öneriliyor. Fazla karmaşık olmadığı sürece senin de yaptığın gibi aralıkları zincirlemek iyi fikir. (Genel olarak elemanlar üzerinde gezinip tek sonuç üretmek gerektiğinde fold'u öneririm. (reduce zincirleme kullanılamadığından onun yerine yeni olarak fold eklenmişti. (reduce'tan tek farkı, parametrelerinin sırasının farklı olmasıdır.)))

  • keys() pahalı bir işlemdir çünkü tablodaki bütün anahtarları içeren bir dizi oluşturur. Onun yerine, byKey kullanılabilir. (keys()'in yararı ise dizi olduğundan istendiğinde sıralanabilmesidir.) O yüzden ben aşağıdaki programda .byKeyValue kullandım:

Bu kodu beni de uzun süre uğraştırdı. Son hali şu:
import std.stdio;
import std.string;
import std.range;
import std.conv;
import std.algorithm;
 
struct UnitSale {
    int quantity = 0;
    double cost = 0;
}
 
struct TotalCost {
    int quantity = 0;
    double sum = 0;
 
    ref TotalCost opOpAssign(string op)(UnitSale unitSale)
    if (op == "+") {
        this.quantity += unitSale.quantity;
        this.sum += (unitSale.quantity * unitSale.cost);
        return this;
    }
}
 
void main() {
    TotalCost[string] totalCostAndAmountForEachDate;
 
    // Böyle yerel işlevler çok yararlı. Örneğin, totalCostAndAmountForEachDate'e doğrudan erişebiliyoruz.
    void calc(T)(T triple) {
        const date = triple[0];
        const cost = triple[1].to!double;
        const quantity = triple[2].to!int;
 
        auto curValPtr = (date in totalCostAndAmountForEachDate);
        if (!curValPtr) {
            totalCostAndAmountForEachDate[date] = TotalCost(0, 0);
            curValPtr = (date in totalCostAndAmountForEachDate);
        }
 
        (*curValPtr) += UnitSale(quantity, cost);
    }
 
    stdin
        .byLine
        .map!(a => a.split(";"))
        .map!(a => a.indexed([10,20,21]))
        .each!(triple => calc(triple));
 
    totalCostAndAmountForEachDate
        .byKeyValue
        .each!(cost => writeln("VWAP for date: ", cost.key, " is " , cost.value.sum / cost.value.quantity));
}
Ali
kerdemdemir #3
Üye Eyl 2013 tarihinden beri · 53 mesaj
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Ali Hocam,

Acaba "Associative array" ler kullanılmadan "std.group" fonksiyonu ile tamemen aralıklar aracılığıyla yapılabilirmiydi diye düşünüyorum deneme fırsatım olmadı bir sorayım dedim.

Sevgiler
Erdemdem
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4391 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
group, gruplanacak elemanların art arda (consecutive) olmalarını gerektiriyor. Eğer veri o biçimdeyse olur sanırım.

Ali
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-04-30, 11:40:35 (UTC -07:00)