HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Grouping queries

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
queriesgroupingstackoverflow

Problem

I have a list of Options. From that list:

-
First I want to get only Drink (the where clause).

-
Then I want to group them by their SortOrder (range of 100).

-
I can stop there and loop through the items and create checkboxes for each items. But I got a requirement that if the OptionGroupName=Alcohol then I need to create radio list instead of checkboxes.

Here's the code that does grouping using Linq:

Option[] options = GetOptions();
var groupedOptions = from option in options
    where option.OptionType == OptionType.Drinks
    group option by option.SortOrder / 100 into grouped
    select new { 
    SortOrderGroup = grouped.Key,
    GroupName = grouped.FirstOrDefault().OptionGroupName
    ,SubGroup= grouped
};


Here's the JSON I get. That's what I want:

So now I can check on client-side if GroupName="Alcohol" generate radio buttons else generate checkboxes.

```
[
{
"SortOrderGroup": 3,
"GroupName": "Soft",
"SubGroup": [
{
"OptionId": 1,
"DisplayName": "Coke",
"OptionType": 2,
"SortOrder": 300,
"OptionGroupName": "Soft"
},
{
"OptionId": 2,
"DisplayName": "Pepsi",
"OptionType": 2,
"SortOrder": 301,
"OptionGroupName": "Soft"
},
{
"OptionId": 3,
"DisplayName": "Sprite",
"OptionType": 2,
"SortOrder": 302,
"OptionGroupName": "Soft"
}
]
},
{
"SortOrderGroup": 4,
"GroupName": "Fruit",
"SubGroup": [
{
"OptionId": 4,
"DisplayName": "Apple Juice",
"OptionType": 2,
"SortOrder": 406,
"OptionGroupName": "Fruit"
},
{
"OptionId": 1,
"DisplayN

Solution

So we're looking at a LINQ query:

Option[] options = GetOptions();
var groupedOptions = from option in options
    where option.OptionType == OptionType.Drinks
    group option by option.SortOrder / 100 into grouped
    select new { 
    SortOrderGroup = grouped.Key,
    GroupName = grouped.FirstOrDefault().OptionGroupName
    ,SubGroup= grouped
};


You went with query syntax - let's see what the method syntax would look like:

var options = GetOptions(); // some IEnumerable - who cares that it's an array?

options.Where(option => option.OptionType == OptionType.Drinks)
       .GroupBy(option => option.SortOrder / 100)
       .Select(grouped => new 
           { 
               Grouping = grouped.Key, 
               Name = grouped.FirstOrDefault().OptionGroupName),
               SubGroup = grouped 
           });


The FirstOrDefault() call will return a null when grouped has no items - that's not really a possibility here, but just because FirstOrDefault itself can return a null, accessing .OptionGroupName on it looks like it's asking for a NullReferenceException. It would be better to use .First() here, because you know a group only exists when it has at least one item...

...but then, you already have an OptionGroupName for each item - why bother selecting the .First at all?

I'd probably write your query like this:

options.Where(option => option.OptionType == OptionType.Drinks)
       .GroupBy(option => new
           {
               SortOrder = option.SortOrder / 100, // integer division
               GroupName = option.OptionGroupName
           })
       .Select(grouping => new 
           { 
               SortOrder = grouping.Key.SortOrder, 
               Name = grouping.Key.GroupName,
               SubGroup = grouping 
           });


Notice I don't care what type GetOptions() is returning - all I'm interested in, is that whatever it's returning implements IEnumerable so that I can LINQ over it - and the plural name is all I need to see to infer I'm dealing wiht an IEnumerable :)

GetOptions shouldn't be returning an array (a concrete type) - it should return an abstraction - IEnumerable in this case.

Code Snippets

Option[] options = GetOptions();
var groupedOptions = from option in options
    where option.OptionType == OptionType.Drinks
    group option by option.SortOrder / 100 into grouped
    select new { 
    SortOrderGroup = grouped.Key,
    GroupName = grouped.FirstOrDefault().OptionGroupName
    ,SubGroup= grouped
};
var options = GetOptions(); // some IEnumerable - who cares that it's an array?

options.Where(option => option.OptionType == OptionType.Drinks)
       .GroupBy(option => option.SortOrder / 100)
       .Select(grouped => new 
           { 
               Grouping = grouped.Key, 
               Name = grouped.FirstOrDefault().OptionGroupName),
               SubGroup = grouped 
           });
options.Where(option => option.OptionType == OptionType.Drinks)
       .GroupBy(option => new
           {
               SortOrder = option.SortOrder / 100, // integer division
               GroupName = option.OptionGroupName
           })
       .Select(grouping => new 
           { 
               SortOrder = grouping.Key.SortOrder, 
               Name = grouping.Key.GroupName,
               SubGroup = grouping 
           });

Context

StackExchange Code Review Q#84698, answer score: 8

Revisions (0)

No revisions yet.