Thread overview
D ile "Hacim ağırlık ortalama fiyat" hesaplaması
Jul 13, 2016
kerdemdemir
Jul 18, 2016
kerdemdemir
July 14, 2016

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 520 + 810 / 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 gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

July 14, 2016
  • İç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

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

July 18, 2016

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

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

July 19, 2016

group, gruplanacak elemanların art arda (consecutive) olmalarını gerektiriyor. Eğer veri o biçimdeyse olur sanırım.

Ali

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