Has anyone implemented or given any thought to how you would implement GroupBy behavior in a business list?
We have a couple of use-cases where we are applying a multi-column sort to our list then checking for changes in the column values as we iterate through the list so that we can render the items in the desired groupings.
As an example, let's say we extended the sample ProjectTracker application to identify the Customer for each Project and we want to be able to view projects, grouped by customer and the start month. So, our GroupBy phrase would be, "Customer, Month(StartDate)" - or something. To do this, we have the following code in place now:
string customer = "";
int month = 0;
foreach (Project p in Projects)
{
if (p.Customer != customer)
{
newCustomer = true;
newMonth = true;
}
else if (p.StartDate.Month != month)
newMonth = true;
if (newCustomer)
{
// Render Customer group row
}
if (newMonth)
{
// Render Month group row
}
// Render (normal) Project row
}
Projects is a SortedList with "Customer, StartDate, Name" as the sort expression.
It would be great if we could something like:
foreach (X customerGroup in Projects.GroupBy("Customer"))
{
// Render Customer group row
foreach (X monthGroup in customerGroup.GroupBy("Month(StartDate)"))
{
// Render Month group row
foreach (Project p in monthGroup)
// Render (normal) Project row
}
}
At a minimum, I'd be interested if anyone has even implemented just a single level GroupBy (e.g. by Customer).
Any thoughts, ideas or suggestions???
Thx.
Yea, I'd thought of that. But (and I admit I am still learning Linq, so I may be off a bit), the "collection" created by Linq would be no different than what we already possess - a list of objects with properties that correspond to the groupings and sorted on those properties. I don't believe Linq behaves any differently than if we used a GroupBy clause in SQL (not meant to be true SQL!):
SELECT * FROM Projects ORDER BY Customer, StartDate, Name GROUP BY Customer, StartDate
would result in:
Customer | StartDate | Name | etc. |
Acme Acres | 1/1/07 | Project1 | ... |
Acme Acres | 6/1/07 | Project2 | ... |
Acme Industries | 3/1/07 | Project3 | ... |
Acme Industries | 3/15/07 | Project4 |
This is the same as if we used a SortedList sorted on Customer, StartDate and Name. The key is how to now access the data in a GroupBy way - almost heirarchically - with the underlying data that our business list contains unchanged.
Thx.
Not sure if I missed the point here entirely but...
On my web screens I sometimes use nested repeaters to give the effect of grouping.
This uses 2 collections. The first collection provides the Group ID and the 2nd is filtered by that ID to return only the rows for that group. This is repeated until the first collection is exhausted.
Joe
Andy - Yea, we could build the heirarchy that way but that still doesn't help us group by date, for instance. And, in this case (although I could change it), the Customer field is strictly a text-field - so perhaps Customer was a bad example.
Joe - Who's doing the filtering? And where does the GroupID come from? That's getting to where I am.
If I can make a quick assumption from what you are describing, it sounds like you have a notion of groups coded or defined in your app. For our needs, the notion of a group is completely dynamic and user-defined at run-time. There is no "GroupID" per se.
Curelom - I'm not proficient in WPF yet, so I'll have to take a closer look at those two classes and how they work. While I do not believe that they will do the trick because they are part of the UI framework and we need this behavior in our BO libraries to share across multiple platforms, presentation layers, etc, it does appear that I might be able to get some insight in how MS has structured this behavior by looking at these classes. To early to tell.
Thx.
Perhaps someone can give me an example of the LINQ code used to accomplish this. I still am not seeing how this saves me anything and that may be the key to my understanding.
Again, the goal is to provide a single, encapsulated business object/list that can be provided to another BO or UI developer to consume. I don't want them to have to know or handle the logic described in my initial post - for a couple of reasons. One, it slows development time. And, two, there's a ton of duplication when this structure exists all over our applications.
With groupby in linq, it actuall gets you an IGrouping IEnumerable that you can use in a foreach to grab each of the groups.
for example the following code groups by the length of the string
string[] names = { "Albert", "Burke", "Connor", "David",
"Everett", "Frank", "George", "Harris"};
// group by length
var groups = names.GroupBy(s => s.Length, s => s[0]);
foreach (IGrouping<int, char> group in groups) {
Console.WriteLine("Strings of length {0}", group.Key);
foreach (char value in group)
Console.WriteLine(" {0}", value);
}
would produce the following output
Strings of length 6More details at http://msdn2.microsoft.com/en-us/library/bb308959.aspx
EXCELLENT!
Now I see what you were getting at and that does address my lack of understanding. I will delve into the article more...
Pardon my ignorance of LINQ (I'm reading as fast as I can!), but where does GroupBy come from and what type(s) does it apply to? Can it be used on any enumerable?
So, does this mean the end of SortedList, FilteredList, etc???
Copyright (c) Marimer LLC