5
\$\begingroup\$

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,
                "DisplayName": "Orange Juice",
                "OptionType": 2,
                "SortOrder": 400,
                "OptionGroupName": "Fruit"
            }
        ]
    },
    {
        "SortOrderGroup": 5,
        "GroupName": "Alcohol",
        "SubGroup": [
            {
                "OptionId": 2,
                "DisplayName": "Wine",
                "OptionType": 2,
                "SortOrder": 501,
                "OptionGroupName": "Alcohol"
            },
            {
                "OptionId": 3,
                "DisplayName": "Beer",
                "OptionType": 2,
                "SortOrder": 502,
                "OptionGroupName": "Alcohol"
            },
            {
                "OptionId": 4,
                "DisplayName": "Rum",
                "OptionType": 2,
                "SortOrder": 520,
                "OptionGroupName": "Alcohol"
            }
        ]
    }
]
\$\endgroup\$
8
\$\begingroup\$

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<T> 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<T> :)

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

\$\endgroup\$
  • 1
    \$\begingroup\$ The GetOptions is a 3rd party service call that returns an Array. I will try out your suggestion. \$\endgroup\$ – gbs Mar 23 '15 at 20:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.