views:

104

answers:

5

I'm working in c#. I have a sorted List of structures. The structure has a DateTime object which stores month and year and an integer which stores a value. The list is sorted by date. I need to traverse the list and combine it so that I only have one instance of the structure per date.

For example: My initial list would look like this:

{ (Apr10, 3), (Apr10, 2), (Apr10, -3), (May10, 1), (May10, 1), (May10, -3), (Jun10, 3) } 

The resulting list should look like this:

{ (Apr10, 2), (May10, -1), (Jun10, 3) }

I'm looking for a simple / efficient solution.

The struct is:

struct CurrentTrade
{
    public DateTime date;
    public int dwBuy;
}

The list is:

private List<CurrentTrade> FillList
+6  A: 

You can use LINQ:

var newList = (
    from trade in FillList
    group trade by trade.Date.Date into g
    select new CurrentTrade { date = g.Key, dwBuy = g.Sum(t => t.dwBuy) }
).ToList();
SLaks
I'm not familiar with LINQ. Can you recommend a site to familiarize myself with the syntax?
Addie
http://msdn.microsoft.com/en-us/netframework/aa904594.aspx
SLaks
http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx and http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx should provide you with some basic facts.
Obalix
Thanks for the LINQ intro. This is going to be very useful.
Addie
+1  A: 

Look at LINQ statements.

Timmy
+1  A: 
var result  = FillList.GroupBy(x => x.date)
                      .Select(g => new CurrentTrade { 
                          date = g.Key, 
                          dwBuy = g.Sum(x => x.dwBuy) 
                      })
                      .ToList();

Edit:

If CurrentTrade does contain a time component you should convert it to a date only DateTime object:

var result  = FillList.GroupBy(x => x.date.Date)
                      .Select(g => new CurrentTrade { 
                          date = g.Key, 
                          dwBuy = g.Sum(x => x.dwBuy) 
                      })
                      .ToList();
Obalix
This will not work. (The trades are at different times)
SLaks
Not necessarily, it depends on the code that is not shown in the OP. If CurrentTrade was constructed with, e.g. date = DateTime.Now.Date this will work. The sample data does not contain times at all so Larry and I just made an assumption based on the facts of the OP.
Obalix
A: 

What about using a HashSet<T>? HashSets can't contain the same object twice. That may however require you to reimplement the GetHash method in your CurrentTrade class.

(Something easy like return Date.GetHashCode() ^ dwBug could do it though.)

zneak
+2  A: 

If you don't want to use LINQ:

If the list is sorted by dates, then all the items with the same dates are next to each other. You can do something like this:

for ( int i = FillList.Count - 1; i >= 1; i-- ) {
    if ( FillList[i].date == FillList[i-1].date ) {
       FillList[i-1].dwBuy += FillList[i].dwBuy;
       FillList.RemoveElementAt( i );
    }
}

The LINQ solution is recommended though, if your .NET supports it.

If the input dates include the time component and you want to merge on the date, just change the if statement from:

if ( FillList[i].date == FillList[i-1].date )

to

if ( FillList[i].date.Date == FillList[i-1].date.Date )
Larry
This will not work. (The trades are at different times) Also, it won't handle three trades on the same date correctly.
SLaks
The statement does explicitly just states the Date (though in a DateTime), but it's trivial to change if time is included.
Larry
This is actually the approach I started with and ran into problems before I posted this question.
Addie
What problems are you running into? I had a typo in my first edit - if you change the order of the for loop it should be fine.
Larry
@Larry The problem was with my approach not yours. Thanks for your help I went with the LINQ approach and it worked perfectly!
Addie