JP Hellemons
JP Hellemons

Reputation: 6047

Linq group by distinct and iterate over it

I want to list all categories of all published posts. But I would like to display categories just once. The Post class has a prop Posts and a constructor for the Categories prop. It's an string array instead of List and I would like to keep it that way.

public class Post
{
    public static List<Post> Posts = LoadPosts();
}

public Post()
{
    ID = Guid.NewGuid().ToString();
    Categories = new string[0]; //array, no List<string>
}

This is my razor markup

<ul class="categories">
    @{var cl = Post.Posts.Where(p => p.IsPublished).Select(c => new List<string>(c.Categories));}
    @foreach (var cat in cl.Distinct())
    {
        <li>@cat</li>
    }
</ul>

This gives me as output

System.Collections.Generic.List`1[System.String]

I have done something wrong in my Linq, but I am not experienced enough (or awake) to see my mistake.

Upvotes: 1

Views: 261

Answers (1)

SWeko
SWeko

Reputation: 30892

What you need is the SelectMany method:

Post.Posts
   .Where(p => p.IsPublished)  // IEnumerable<Post>
   .SelectMany(c => c.Categories) // IEnumerable<string>
   .Distinct()

It seems odd, but the real counterpart to the SQL select is not the IEnumerable.Select method, but the IEnumerable.SelectMany, because it can "flatten" the result of the selection, while Select makes a separate collection for each element, resulting in:

Post.Posts
  .Where(p => p.IsPublished)  // IEnumerable<Post>
  .Select(c => c.Categories) // IEnumerable<IEnumerable<string>>
  .Distinct() // does nothing, since all inner IEnumerable<string> 
              // objects are different

Upvotes: 3

Related Questions