bkingdev
bkingdev

Reputation: 237

How to use LINQ to return a query result to a dictionary

I am working on an MVC project. I need to return an object that groups menu items into groups of four to display in the view using foreach iteration. As this is a model being passed to the view, I need to return a non-generic collection class that can be bound on the .cshtml.

My thought is that I could group the list based on some type of count within LINQ to add four new List items to every Dictionary key. However, I haven't found an expression that would suffice to a Dictionary. I could solve this rather easily by creating another method and iterating again through the collection to assign keys based on a count, but it seems like unneeded iteration and bad practice.

Currently, I am working with the following query.

        var itemsDict = rssDataContext.rss_Application_Blog_Category_Relationships
            .Where(x => x.Application_Blog.rss_Application.ID == 1)
            .Where(x => x.Blog_Category_ID == 1)
            .Select(x => new MenuItem
            {
            Name = x.rss_Application_Blog.Blog_Title,
            Uri = x.rss_Application_Blog.Blog_Uri,
            ID = x.rss_Application_Blog.ID
            });

But is there a way to group this query into groups of 4 class that be populated into Dictionary<int, List<MenuItem>>?

Upvotes: 1

Views: 488

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1501163

I suspect you could do this:

var itemsDict = rssDataContext.rss_Application_Blog_Category_Relationships
    .Where(x => x.Application_Blog.rss_Application.ID == 1)
    .Where(x => x.Blog_Category_ID == 1)
    .Select(x => new { 
        x.rss_Application_Blog.BlogTitle,
        x.rss_Application_Blog.BlogUri,
        x.rss_Application_Blog.ID
    })
    .AsEnumerable() // Do the rest of the query in-process
    .Select((value, index) => new { value, index })
    .ToLookup(pair => pair.index % 4,
              pair => new MenuItem {
                 Name = pair.value.Blog_Title,
                 Uri = pair.value.Blog_Uri,
                 ID = pair.value.ID
              });

Note that this returns a Lookup rather than a Dictionary, but that's actually a closer model for what you want.

Upvotes: 3

Enrico Campidoglio
Enrico Campidoglio

Reputation: 59923

@JonSkeet's solution is pretty good. Here's an alternative implementation using GroupBy to create the sublists and ToDictionary to project them into the final result:

var itemsDict = rssDataContext.rss_Application_Blog_Category_Relationships
    .Where(x => x.Application_Blog.rss_Application.ID == 1)
    .Where(x => x.Blog_Category_ID == 1)
    .ToArray()
    .Select((x, index) => new
        {
            Index = index,
            Item = new MenuItem
            {
                Name = x.rss_Application_Blog.Blog_Title,
                Uri = x.rss_Application_Blog.Blog_Uri,
                ID = x.rss_Application_Blog.ID
            }
        });
    .GroupBy(i => i.Index / 4)
    .ToDictionary(g => g.Key);

The resulting sequence will look something like this:

items = new Dictionary<int, IGrouping<int>>()
{
    0, new[]
    {
        new { Index = 0, Item = new MenuItem { ... } },
        new { Index = 1, Item = new MenuItem { ... } }
    }
    1, new[]
    {
        new { Index = 2, Item = new MenuItem { ... } },
        new { Index = 3, Item = new MenuItem { ... } }
    }
};

Upvotes: 2

Related Questions