Reputation: 7266
I have this C# class:
public class Option
{
public int OptionId { get; set; }
public string OptionName { get; set; }
public string OptionType { get; set; } //Three different types A,B,C
public int SortOrder { get; set; } //100-199, 200-299, etc.
}
GetOptions returns an array Option[].
Now what I want:
First: Group the options by OptionType
Then: Group the items within the first group by SortOrder, with condition that option with SortOrder between 100-199 should be in one group, 200-299 in another and so forth.
I am able to do the first like:
IEnumerable<IGrouping<string, Option>> groupedOptions =
from option in options
group option by option.OptionType;
or this
var groupedOptions2 = options.GroupBy(p=>p.OptionType);
Second I don't know how to. I tried adding another GroupBy but that didn't work. Sure doing something wrong.
Thanks.
Update: I got it working using nested repeater but am not really sure if that is the right way or not.
I get the options using the first query I have above: groupedOptions
Bind it to the Repeater. Display the OptionType in that Repeater. In the databound event of the repeater I do another grouping:
IGrouping<OptionType, Option> itm =(IGrouping<OptionType, Option>) e.Item.DataItem;
IEnumerable<IGrouping<int, Option>> nestedGroupedOptions =
from option in itm
group option by option.SortOrder/100;
Then I bind that to the inner repeater which has a checkboxlist. Here's my entire .aspx test page. It is a stand alone page and can be tested by dropping it inside an asp.net webforms website.
<%@ Page Language="C#" %>
<!DOCTYPE html>
<script runat="server">
Dictionary<int, string> OptionGroupNames = null;
protected void Page_Load(object sender, EventArgs e)
{
OptionGroupNames = GetOptionGroupNames();
DisplayDrinks();
}
public void DisplayDrinks()
{
Option[] options = GetOptions();
IEnumerable<IGrouping<OptionType, Option>> groupedOptions =
from option in options
group option by option.OptionType;
rptrGroupOptions.DataSource = groupedOptions;
rptrGroupOptions.DataBind();
}
protected void rptrGroupOptions_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
IGrouping<OptionType, Option> itm = (IGrouping<OptionType, Option>)e.Item.DataItem;
Label lblHeader = e.Item.FindControl("lblOptionGroup") as Label;
Repeater rptrOptions = e.Item.FindControl("rptrOptions") as Repeater;
lblHeader.Text = itm.Key.ToString();
IEnumerable<IGrouping<int, Option>> groupedOptions =
from option in itm
group option by option.SortOrder / 100;
rptrOptions.DataSource = groupedOptions;
rptrOptions.DataBind();
}
}
protected void rptrOptions_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
IGrouping<int, Option> itm = (IGrouping<int, Option>)e.Item.DataItem;
CheckBoxList cbl = e.Item.FindControl("cblOptions") as CheckBoxList;
Label lblOptionGroup = e.Item.FindControl("lblOptionGroupNum") as Label;
if (itm.Key != 1 && itm.Key != 2)
{
lblOptionGroup.Text = OptionGroupNames.First(p => p.Key == itm.Key).Value;
}
cbl.DataSource = itm;
cbl.DataBind();
}
}
public Option[] GetOptions()
{
var Options = new Option[]{
new Option{OptionId=1, DisplayName="Green", OptionType = OptionType.Tea, SortOrder=100},
new Option{OptionId=2, DisplayName="Black", OptionType = OptionType.Tea, SortOrder=101},
new Option{OptionId=3, DisplayName="French", OptionType = OptionType.Coffee, SortOrder=202},
new Option{OptionId=4, DisplayName="Espresso", OptionType = OptionType.Coffee, SortOrder=206},
new Option{OptionId=4, DisplayName="Cappuccino", OptionType = OptionType.Coffee, SortOrder=250},
new Option{OptionId=1, DisplayName="Coke", OptionType = OptionType.Drinks, SortOrder=300},
new Option{OptionId=2, DisplayName="Pepsi", OptionType = OptionType.Drinks, SortOrder=301},
new Option{OptionId=3, DisplayName="Sprite", OptionType = OptionType.Drinks, SortOrder=302},
new Option{OptionId=4, DisplayName="Apple Juice", OptionType = OptionType.Drinks, SortOrder=406},
new Option{OptionId=1, DisplayName="Orange Juice", OptionType = OptionType.Drinks, SortOrder=400},
new Option{OptionId=2, DisplayName="Wine", OptionType = OptionType.Drinks, SortOrder=501},
new Option{OptionId=3, DisplayName="Beer", OptionType = OptionType.Drinks, SortOrder=502},
new Option{OptionId=4, DisplayName="Rum", OptionType = OptionType.Drinks, SortOrder=520}
};
return Options.ToArray();
}
public static Dictionary<int, string> GetOptionGroupNames()
{
Dictionary<int, string> optionGroups = new Dictionary<int, string>();
optionGroups.Add(1, "Tea");
optionGroups.Add(2, "Coffee");
optionGroups.Add(3, "Soda");
optionGroups.Add(4, "Juice");
optionGroups.Add(5, "Alcohol");
return optionGroups;
}
public class Option
{
public int OptionId { get; set; }
public string DisplayName { get; set; }
public OptionType OptionType { get; set; } //Three different types A,B,C
public int SortOrder { get; set; } //100-199, 200-299, etc.
}
public enum OptionType
{
Coffee,
Tea,
Drinks
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="rptrGroupOptions" runat="server" OnItemDataBound="rptrGroupOptions_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblOptionGroup" runat="server" ForeColor="Maroon"></asp:Label><br />
<asp:Repeater ID="rptrOptions" runat="server" OnItemDataBound="rptrOptions_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblOptionGroupNum" runat="server" ForeColor="Sienna"></asp:Label>
<asp:CheckBoxList ID="cblOptions" runat="server" DataTextField="DisplayName" DataValueField="OptionId"></asp:CheckBoxList>
</ItemTemplate>
</asp:Repeater>
<br />
</ItemTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
Sorry I am still trying to get hold of Linq and GroupBy.
Upvotes: 1
Views: 134
Reputation: 39326
I think you could do something like this:
var result= options.ToLookup(o => o.OptionType).
ToDictionary(grouping => grouping.Key, grouping => grouping.
ToLookup(o => o.SortOder/100));
This way, you have a dictionary where the key is the OptionType
and the value is a group of Option
according your range of values.
Upvotes: 0
Reputation: 168
I would do it like this way:
options.GroupBy(x => new { x.OptionType, Group = x.SortOder / 100 })
You will get key objects like ( "A", 1 ) ("B", 1) ("B", 2)
with the original object as value.
Upvotes: 1