LINQ and lambdas - Get control of your data - group
Head First C Sharp: A Learner’s Guide to Real-World Programming with C Sharp and .NET (Andrew Stellman(著)、Jennifer Greene(著)、O’Reilly Media)の Chapter 9(LINQ and lambdas - Get control of your data)、p.497(Exercise)の解答を求めてみる。
コード
Program.cs
using System.Runtime.InteropServices.Marshalling;
using JimmyLinq;
namespace JimmyLinq
{
internal class Program
{
static void Main(string[] args)
{
var done = false;
while (!done)
{
Console.WriteLine(
"\nPress G to group comics by price, R to get reviews, any other key to quit\n");
switch (Console.ReadKey(true).KeyChar.ToString().ToUpper())
{
case "G":
done = GroupComicsByPrice();
break;
case "R":
done = GetReviews();
break;
default:
done = true;
break;
}
}
}
private static bool GroupComicsByPrice()
{
var groups = ComicAnalyzer.GroupComicsByPrice(Comic.Catalog, Comic.Prices);
foreach (var group in groups)
{
Console.WriteLine($"{group.Key} comics");
foreach (var comic in group)
{
Console.WriteLine($"#{comic.Issue} {comic.Name}: {Comic.Prices[comic.Issue]:c}");
}
}
return false;
}
private static bool GetReviews()
{
var reviews = ComicAnalyzer.GetReviews(Comic.Catalog, Comic.Reviews);
foreach (var review in reviews)
{
Console.WriteLine(review);
}
return false;
}
private static class ComicAnalyzer
{
private static PriceRange CalculatePriceRange(Comic comic)
{
if (Comic.Prices[comic.Issue] < 100)
{
return PriceRange.Cheap;
}
return PriceRange.Expensive;
}
public static IEnumerable<IGrouping<PriceRange, Comic>> GroupComicsByPrice(IEnumerable<Comic> catalog, IReadOnlyDictionary<int, decimal> prices)
{
return from comic in catalog
orderby prices[comic.Issue]
group comic by CalculatePriceRange(comic) into grouped
select grouped;
}
public static IEnumerable<object> GetReviews(IEnumerable<Comic> catalog, IEnumerable<Review> reviews)
{
return from comic in catalog
orderby comic.Issue
join review in reviews
on comic.Issue equals review.Issue
select $"{review.Critic} rated #{comic.Issue} '{comic.Name}' {review.Score:0.00}";
}
}
}
}
Comic.cs
namespace JimmyLinq;
public class Comic
{
public string Name { get; set; } = "";
public int Issue { get; set; }
public override string ToString()
{
return $"{Name} (Issue #{Issue})";
}
public static readonly IEnumerable<Comic> Catalog =
new List<Comic>{
new Comic(){Name="Johnny America vs. the Pinko", Issue=6},
new Comic(){Name="Rock and Roll (limitededition)", Issue=19},
new Comic(){Name="Woman's Work", Issue=36},
new Comic(){Name="Hippie Madness (misprinted)", Issue=57},
new Comic(){Name="Revenge of the New Wave Freak (damaged)", Issue=68},
new Comic(){Name="Black Monday", Issue=74},
new Comic(){Name="Tattoo Madness", Issue=83},
new Comic(){Name="The Death of the Object", Issue=97},
};
public static readonly IEnumerable<Review> Reviews = new[]
{
new Review() { Issue = 36, Critic = Critics.MuddyCritic, Score = 37.6},
new Review() { Issue = 74, Critic = Critics.RottenTornadoes, Score =22.8 },
new Review() { Issue = 74, Critic = Critics.MuddyCritic, Score = 87.2 },
new Review() { Issue = 83, Critic = Critics.RottenTornadoes, Score = 89.4 },
new Review() { Issue = 97, Critic = Critics.MuddyCritic, Score = 98.1 },
};
public static readonly IReadOnlyDictionary<int, decimal> Prices =
new Dictionary<int, decimal>{
{6, 3600M},
{19,500M},
{36,650M},
{57,13525M},
{68,250M},
{74,75M},
{83,25.75M},
{97,35.25M},
};
}
Critics.cs
namespace JimmyLinq;
public enum Critics
{
MuddyCritic,
RottenTornadoes,
}
PriceRange.cs
namespace JimmyLinq;
public enum PriceRange
{
Cheap,
Expensive
}
Review.cs
namespace JimmyLinq;
public class Review
{
public int Issue { get; set; }
public Critics Critic { get; set; }
public double Score { get; set; }
}
入出力結果(Terminal, Zsh)
% dotnet run
Press G to group comics by price, R to get reviews, any other key to quit
Cheap comics
#83 Tattoo Madness: ¥26
#97 The Death of the Object: ¥35
#74 Black Monday: ¥75
Expensive comics
#68 Revenge of the New Wave Freak (damaged): ¥250
#19 Rock and Roll (limitededition): ¥500
#36 Woman's Work: ¥650
#6 Johnny America vs. the Pinko: ¥3,600
#57 Hippie Madness (misprinted): ¥13,525
Press G to group comics by price, R to get reviews, any other key to quit
MuddyCritic rated #36 'Woman's Work' 37.60
RottenTornadoes rated #74 'Black Monday' 22.80
MuddyCritic rated #74 'Black Monday' 87.20
RottenTornadoes rated #83 'Tattoo Madness' 89.40
MuddyCritic rated #97 'The Death of the Object' 98.10
Press G to group comics by price, R to get reviews, any other key to quit
MuddyCritic rated #36 'Woman's Work' 37.60
RottenTornadoes rated #74 'Black Monday' 22.80
MuddyCritic rated #74 'Black Monday' 87.20
RottenTornadoes rated #83 'Tattoo Madness' 89.40
MuddyCritic rated #97 'The Death of the Object' 98.10
Press G to group comics by price, R to get reviews, any other key to quit
Cheap comics
#83 Tattoo Madness: ¥26
#97 The Death of the Object: ¥35
#74 Black Monday: ¥75
Expensive comics
#68 Revenge of the New Wave Freak (damaged): ¥250
#19 Rock and Roll (limitededition): ¥500
#36 Woman's Work: ¥650
#6 Johnny America vs. the Pinko: ¥3,600
#57 Hippie Madness (misprinted): ¥13,525
Press G to group comics by price, R to get reviews, any other key to quit
%