Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group List of Objects based on Property using Linq?

I have an object:

public class SiteInfo
        {
            public string Title { get; set; }
            public string URL { get; set; }
            public string Type { get; set; }     
        }

That I am using to create a list: var sites = new List();

        foreach (SPWeb site in web.GetSubwebsForCurrentUser())
        {
            string sitetype = getConfigurationKey(site, "siteType");
            //If sites have a site type then add to list
            if (sitetype != "*ERROR*" && sitetype != "*KEYNOTFOUND*")
            {
                SiteInfo s = new SiteInfo();
                s.Title = site.Title;
                s.URL = site.Url;
                s.Type = sitetype;

                sites.Add(s);
            }
        }
        //sort list by type
        sites.Sort((x, y) => string.Compare(x.Type, y.Type));

        // serialize and send..    
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        StringBuilder sbJsonResults = new StringBuilder();
        serializer.Serialize(sites, sbJsonResults);
etc.....

However what I would like to do is group the sites by Type prior to serializing them. Is this possible using LINQ or some other method.

like image 362
BlueBird Avatar asked Feb 01 '13 19:02

BlueBird


3 Answers

It sounds like you want something like:

// No need to sort sites first
var grouped = sites.OrderBy(x => x.Type)
                   .GroupBy(x => x.Type);

Then just serialize grouped. However, I don't know quite what an IGrouping will look like in JSON... and the type will be present in each case. You may want something like:

var grouped = sites.OrderBy(x => x.Type)
                   .GroupBy(x => x.Type)
                   .Select(g => new { Type = g.Key,
                                      Sites = g.Select(site => new {
                                                           site.Title,
                                                           site.URL
                                                       } });

I think that would give you a nicer JSON structure.

like image 168
Jon Skeet Avatar answered Nov 09 '22 16:11

Jon Skeet


This

var sites = new List<SiteInfo>()
{
    new SiteInfo(){Title="1",Type="a",URL="http://aaaa"},
    new SiteInfo(){Title="2",Type="b",URL="http://bbbb"},
    new SiteInfo(){Title="3",Type="a",URL="http://aaaa"},
    new SiteInfo(){Title="4",Type="b",URL="http://bbb"},
};

var json = new JavaScriptSerializer().Serialize(sites.GroupBy(s => s.Type));

would produce

[
    [{"Title":"1","URL":"http://aaaa","Type":"a"},{"Title":"3","URL":"http://aaaa","Type":"a"}],
    [{"Title":"2","URL":"http://bbbb","Type":"b"},{"Title":"4","URL":"http://bbb","Type":"b"}]
]

or

var json = new JavaScriptSerializer().Serialize(sites.GroupBy(s => s.Type)
                                                      .ToDictionary(x=>x.Key,x=>x));

would produce

{
    "a":[{"Title":"1","URL":"http://aaaa","Type":"a"},{"Title":"3","URL":"http://aaaa","Type":"a"}],
    "b":[{"Title":"2","URL":"http://bbbb","Type":"b"},{"Title":"4","URL":"http://bbb","Type":"b"}]
}
like image 36
I4V Avatar answered Nov 09 '22 16:11

I4V


Here's a straightforward console application that does what you want:

static void Main(string[] args)
{
    List<SiteInfo> sites = new List<SiteInfo>()
    {
        new SiteInfo() { Title = "Site A", Type = "Whatever 2" },
        new SiteInfo() { Title = "Site B", Type = "Whatever 1" },
        new SiteInfo() { Title = "Site C", Type = "Whatever 1" },
        new SiteInfo() { Title = "Site D", Type = "Whatever 3" },
        new SiteInfo() { Title = "Site E", Type = "Whatever 3" }
    };

    var sitesGroupedByType =
        sites.GroupBy(s => s.Type).Select(g => new { Type = g.Key,
                                    Sites = g.Select(site => new
                                    {
                                          site.Title,
                                          site.URL
                                    })});

    foreach (var siteTypeGroup in sitesGroupedByType.OrderBy(g => g.Type))
    {
        foreach(var site in siteTypeGroup.Sites)
        {
            Console.WriteLine(string.Format("Type => {0}, Title => {1}",
                              siteTypeGroup.Type, site.Title));
        }
    }

    Console.ReadKey();
}

Output:

Type => Whatever 1, Title => Site B
Type => Whatever 1, Title => Site C
Type => Whatever 2, Title => Site A
Type => Whatever 3, Title => Site D
Type => Whatever 3, Title => Site E
like image 3
Leniel Maccaferri Avatar answered Nov 09 '22 16:11

Leniel Maccaferri