tags:

views:

83

answers:

3

What I have is a collection named HourList which is made up of Hour objects. Two of the properties on an Hour are EmployeeId and Hours. Employees punch in and out and an hour record is created. So at the end of a week I am delivered an HourList of mulipple Hour objects for mulitple employees from our DAO. It is requested that a report be made where only employees with total hours above a given threshold are displayed.

Example: A simple and flattened HourList

Id | Hours
----------
1  | 4.5
2  | 6.0
3  | 9.9
1  | 5.5
2  | 2.5

The threshold is 10. In this case I would only want an Id 1's hour records, since his summed hours exceed 10.

I know I could do this by creating a new DAO method to handle this when I return the initial HourList. I also can do this very inefficiently with a foreach statement. I am trying to get better with Linq though and would like to see what's possible. Thank you for any help in advance.

+4  A: 
var filtered = HourList.GroupBy(h => h.id)
                       .Select(g => new { Id = g.Key,
                                          Hours = g.Sum(h => h.Hours)
                                        })
                       .Where(h => h.Hours >= 10);

Can't test it, but this should get you close.

Justin Niessner
yep, EXACT same code as I have...it works.
Stan R.
@Justin and Stan, thanks guys. That does look like it will work, but sorry for the novice question...what do I do with the Var filtered? It appears the .Select returns an IEnumerable<IGrouping<Id,Hour>>. How can I use this? Do we have to loop again and store it into something else?
TForceDeveloper
@TForceDeveloper - filtered should contain an Enumerable collection of Anonymous types. The type should have two properties, ID and Hours.
Justin Niessner
Returning HourEntry objects instead of anonymous objects would be more useful.
Douglas
I see that after seeing Matt's posting. Thanks everyone for the help.
TForceDeveloper
I set this as the accepted answer, but really everyone's answers would work so...is there a way to give credit to all?
TForceDeveloper
+1  A: 
        var hourList = new List<Hour>() 
        { 
            new Hour() { Id = 1, Hours = 4.5M},
            new Hour() { Id = 2, Hours = 6M},
            new Hour() { Id = 3, Hours = 9.9M},
            new Hour() { Id = 1, Hours = 5.5M},
            new Hour() { Id = 2, Hours = 2.5M}
        };

        var over10 = hourList.GroupBy(h => h.Id).Select( h => new { Id = h.Key, Sum = h.Sum( s => s.Hours )}).Where( x => x.Sum >= 10 );
Stan R.
+2  A: 

Here is a quick example that does what you are after:

   class Program
    {
        public class HourEntry
        {
            public int Id { get; set; }
            public int Hours { get; set; }
        }

        static void Main(string[] args)
        {
            List<HourEntry> hours = new List<HourEntry>
            {
                new HourEntry { Id = 1, Hours = 3 },
                new HourEntry { Id = 2, Hours = 4 },
                new HourEntry { Id = 3, Hours = 3 },
                new HourEntry { Id = 1, Hours = 8 },
                new HourEntry { Id = 5, Hours = 2 },
                new HourEntry { Id = 3, Hours = 2 },
                new HourEntry { Id = 3, Hours = 6 },
                new HourEntry { Id = 9, Hours = 2 },
                new HourEntry { Id = 4, Hours = 2 },
            };


            var moreThanTen = from h in hours
                              group h by h.Id into hGroup
                              where hGroup.Sum(hg => hg.Hours) > 10
                              select hGroup.Key;

            foreach (var m in moreThanTen)
            {
                Console.WriteLine(m);
            }
        }
    }
Matt Greer
+1 excellent, somehow I tried to solve it the same way, but got lost in returning the original object (but the OP asked for IDs only). I always prefer this above fluid syntax :)
Abel