Search code examples
c#linqpad

Is there a better way to convert objects in List to show side by side view by date


I would like to reorganize the list of objects and classify them by the date of entry in a side by side view so I can compare the trades across instruments by day. so this view needs to be reorganised from

as the following

to

The only logic I created was to use a Dictionary of dynamo objects. However it forces me to define the columns everytime. Is there a more efficient approach?

code in linqpad share. linqpad share

void Main()
{
    List<STSmyTrade> testoj = new List<STSmyTrade>(); // object 1
    STSmyTrade a1 = new STSmyTrade();
    a1.instrument = "eurusd";
    a1.entryPrice = 3;

    a1.entryTime = DateTime.Now.AddDays(1);
    testoj.Add(a1);
    STSmyTrade a2 = new STSmyTrade();
    a2.instrument = "eurusd";
    a2.entryPrice = 6;
    a2.entryTime = DateTime.Now.AddDays(2);
    testoj.Add(a2);
    
    
    
    STSmyTrade a3 = new STSmyTrade();
    a3.instrument = "audusd";
    a3.entryPrice = 3;
    a3.entryTime = DateTime.Now;
    
    testoj.Add(a3);
    STSmyTrade a4 = new STSmyTrade();
    a4.instrument = "audusd";
    a4.entryPrice = 6;
    a4.entryTime = DateTime.Now.AddDays(2);
    testoj.Add(a4);
    testoj.Dump();

     


    // need to compare the 2 instruments sorted by date

    Dictionary<DateTime, ExpandoObject> analysiscompare = new Dictionary<DateTime, ExpandoObject>();
    foreach (STSmyTrade t in  testoj ) // loop first time comparing before and after
    {
        dynamic eo;
        if (!analysiscompare.Keys.Contains(t.entryTime.Date))// if i dont have a record in the dictionary object, create it.
        
        {
            eo = new ExpandoObject();
             eo.day=t.entryTime.Date.ToString("yyyy-MM-dd");// just assign the day.
            eo.eurusdentryTime = null;
            eo.eurusdentryPrice = null;
            eo.audusdentryTime = null;
            eo.audusdentryPrice = null;
            analysiscompare.Add(t.entryTime.Date, eo);

        }
        //dynamic eo;
 
        eo = analysiscompare[t.entryTime.Date];
        switch (t.instrument)
        {
            case "eurusd":
                eo.eurusdentryTime = t.entryTime;
                eo.eurusdentryPrice = t.entryPrice;
                 
                break;

            case "audusd":
                eo.audusdentryTime = t.entryTime;
                eo.audusdentryPrice = t.entryPrice;
                break;




        }


    }
    analysiscompare.Values.ToList().Dump("side_by_side_view");
     


}


class STSmyTrade
{
public DateTime entryTime { get; set; }
    public string instrument { get; set; }


    public double entryPrice { get; set; }
    
}

The only way, I can make this work is by creating a custom column mapping to each unique object(audusd, eurusd). However this is not scalable.


Solution

  • Assuming you don't have two entries for a currency on the same day, you can group by date and select the eurusd and audusd entries per group, eg.

    (from r in testoj
     group r by r.entryTime.Date into results
     let eur = results.SingleOrDefault(a => a.instrument == "eurusd")
     let aud = results.SingleOrDefault(a => a.instrument == "audusd")
     select new
     {
         day = results.Key.ToString("yyyy-MM-dd"),
         eurusdentryTime  = eur?.entryTime,
         audusdentryTime  = aud?.entryTime,
         eurusdentryPrice = eur?.entryPrice,
         audusdentryPrice = aud?.entryPrice,
    
     }).Dump();
    

    You probably want to sort the results, but your original doesn't seem to be sorted, so I haven't sorted mine either.