#8 Group books by authors in 3 ways
Grouping by Authors, a List inside of Books
GroupBy Authors - bad example
This example will group the books by the Authors
property. This example doesn't give us what we want, because authors that exist in sets and alone are grouped separately.
-
Group
-
Hitchhikers Guide to the Galaxy by
Douglas Adams
-
Group
-
Good Omens by
Neil Gaiman,Terry Pratchett
-
Group
-
Phishing for Phools by
George Akerlof
-
Group
-
The Last Continent by
Terry Pratchett
<ol>
@foreach(var group in books.GroupBy(b => b.Authors)) {
<li>
Group
<ul>
@foreach(var book in group) {
<li>
<strong>@book.Title</strong> by
@string.Join(",",(book.Authors as Dynlist).Select(a => a.FirstName + " " + a.LastName))
</li>
}
</ul>
</li>
}
</ol>
GroupBy Authors - better example
Let's do it better, and group by each Author individually
-
Author: Douglas Adams
-
Hitchhikers Guide to the Galaxy by
Douglas Adams
-
Author: Neil Gaiman
-
Good Omens by
Neil Gaiman,Terry Pratchett
-
Author: Terry Pratchett
-
Good Omens by
Neil Gaiman,Terry Pratchett
-
The Last Continent by
Terry Pratchett
-
Author: George Akerlof
-
Phishing for Phools by
George Akerlof
<ol>
@{
var booksGroupedByAuthor = books
.SelectMany(b => (b.Authors as Dynlist).Select(a => new { Book = b, Author = a }))
.GroupBy(set => set.Author);
foreach(var group in booksGroupedByAuthor) {
<li>
Author: @group.Key.FirstName @group.Key.LastName
<ul>
@foreach(var set in group) {
<li>
<strong>@set.Book.Title</strong> by
@string.Join(",",(set.Book.Authors as Dynlist).Select(a => a.FirstName + " " + a.LastName))
</li>
}
</ul>
</li>
}
}
</ol>
GroupBy Authors - Example starting with Authors
In this example, we'll start with the authors list. This is probably not ideal - as some people are not authors, but it's a good learning example. To find the books we have to navigate through Parents(...)
because in our data-model, the books reference authors, not the authors to books.
-
Douglas Adams
-
Hitchhikers Guide to the Galaxy
-
Terry Pratchett
-
Good Omens
co-authored by
Neil Gaiman
-
The Last Continent
-
Neil Gaiman
-
Good Omens
co-authored by
Terry Pratchett
-
George Akerlof
-
Raphael Müller (not an author)
-
Ed Hardy
<ol>
@foreach(var author in persons) {
// this line would work, if Books only had people in the Authors.
// but it doesn't, there are also illustrators, which is why we use the second example instead
var peoplesBooks = author.Parents("Books");
var authorsBooks = author.Parents("Books", "Authors");
<li>
@author.FirstName @author.LastName
<ul>
@foreach(var book in authorsBooks) {
var coAuthors = (book.Authors as Dynlist).Where(a => a != author);
<li>
<strong>@book.Title</strong>
@if(coAuthors.Any()) {
<span>co-authored by
@string.Join(",", coAuthors.Select(a => a.FirstName + " " + a.LastName))
</span>
}
</li>
}
</ul>
</li>
}
</ol>
#8 Group books by authors in 3 ways
@inherits Custom.Hybrid.Razor14
@using System.Linq;
@using Dynlist = System.Collections.Generic.IEnumerable<dynamic>;
<!-- unimportant stuff, hidden -->
@{
var persons = AsList(App.Data["Persons"]);
var books = AsList(App.Data["Books"]);
}
@Html.Partial("_header.cshtml")
<div class="row">
<div class="col-lg-7">
<h2>Grouping by Authors, a List inside of Books</h2>
</div>
@Html.Partial("../shared/_DefaultInfoSection.cshtml")
</div>
<h3>GroupBy Authors - bad example</h3>
<p>This example will group the books by the <code>Authors</code> property. This example doesn't give us what we want, because authors that exist in sets and alone are grouped separately. </p>
<ol>
@foreach(var group in books.GroupBy(b => b.Authors)) {
<li>
Group
<ul>
@foreach(var book in group) {
<li>
<strong>@book.Title</strong> by
@string.Join(",",(book.Authors as Dynlist).Select(a => a.FirstName + " " + a.LastName))
</li>
}
</ul>
</li>
}
</ol>
<hr>
<h3>GroupBy Authors - better example</h3>
<p>Let's do it better, and group by each Author individually</p>
<ol>
@{
var booksGroupedByAuthor = books
.SelectMany(b => (b.Authors as Dynlist).Select(a => new { Book = b, Author = a }))
.GroupBy(set => set.Author);
foreach(var group in booksGroupedByAuthor) {
<li>
Author: @group.Key.FirstName @group.Key.LastName
<ul>
@foreach(var set in group) {
<li>
<strong>@set.Book.Title</strong> by
@string.Join(",",(set.Book.Authors as Dynlist).Select(a => a.FirstName + " " + a.LastName))
</li>
}
</ul>
</li>
}
}
</ol>
<hr>
<h3>GroupBy Authors - Example starting with Authors</h3>
<p>In this example, we'll start with the authors list. This is probably not ideal - as some people are not authors, but it's a good learning example. To find the books we have to navigate through <code>Parents(...)</code> because in our data-model, the books reference authors, not the authors to books.</p>
<ol>
@foreach(var author in persons) {
// this line would work, if Books only had people in the Authors.
// but it doesn't, there are also illustrators, which is why we use the second example instead
var peoplesBooks = author.Parents("Books");
var authorsBooks = author.Parents("Books", "Authors");
<li>
@author.FirstName @author.LastName
<ul>
@foreach(var book in authorsBooks) {
var coAuthors = (book.Authors as Dynlist).Where(a => a != author);
<li>
<strong>@book.Title</strong>
@if(coAuthors.Any()) {
<span>co-authored by
@string.Join(",", coAuthors.Select(a => a.FirstName + " " + a.LastName))
</span>
}
</li>
}
</ul>
</li>
}
</ol>
<!-- unimportant stuff, hidden -->