Question

I have a hierarchical data arranged in form Groups -> SubGroups -> Items. I want to convert following piece of code in some efficient linq query using SelectMany

IEnumerable<MainGroup> res = <somedata containg hierarchy Groups -> SubGroups -> Items> ;
foreach (var group in res)
{
    foreach (var subgroup in group.SubGroups)
    {
        foreach (var item in subgroup.ItemMps)
        {
            if (item.ItemMpId.ToString() == work.ItemMpID)
            {
                temp = temp + group.MainGroupId + "," + subgroup.SubGroupId + "," +
                        item.ItemMpId + "-|-";
            }
        }
    }
}

Please someone tell me how can i use linq query here. Please note that my requirement is to use SelectMany and my final output needs to have different attributes from all hierarchy levels.

Was it helpful?

Solution

I think you need to use this overload of SelectMany:

http://msdn.microsoft.com/en-us/library/bb534631(v=vs.110).aspx

But I also think you need to call it twice. Given the following structure, I came up with the following:

class Program
{
    static void Main(string[] args)
    {
        var groups = new List<Group>();

        var items = groups
            .SelectMany(group => group.SubGroups, (group, subGroup) => new
                {
                    group,
                    subGroup
                })
            .SelectMany(anon => anon.subGroup.Items, (anon, item) => new
                {
                    Group = anon.group,
                    SubGroup = anon.subGroup,
                    Item = item
                });

        Console.Read();
    }
}

class Group
{
    public string GroupName { get; set; }
    public List<SubGroup> SubGroups { get; set; }
}

class SubGroup
{
    public string SubGroupName { get; set; }
    public List<Item> Items { get; set; }
}

class Item
{
    public string ItemName { get; set; }
}

Basically, you project forward to keep a reference to the parent item. In your specific structure, it would look like this:

var items = groups
    .SelectMany(group => group.SubGroups, (group, subGroup) => new
        {
            group,
            subGroup
        })
    .SelectMany(anon => anon.subGroup.Items, (anon, item) => new
        {
            anon.group.MainGroupId,
            anon.subGroup.SubGroupId,
            item.ItemMpId
        });

This gives you a large list of anonymous type currently not filtered, if you want to filter the stuff as you go simply append a Where call into the Items merge:

var items = groups
    .SelectMany(group => group.SubGroups, (group, subGroup) => new
        {
            group,
            subGroup
        })
    .SelectMany(anon => anon.subGroup.Items.Where(item => item.ItemMpId == work.ItemMpId), (anon, item) => new
        {
            anon.group.MainGroupId,
            anon.subGroup.SubGroupId,
            item.ItemMpId
        });

This should address your requirement of SelectMany usage, however, I'm not convinced this is entirely readable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top