LINQ and lambdas - Get control of your data - refactoring, lambda expressions, switch expressions, LINQ methods(OrderBy, GroupBy, Select, Join)
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.518(Sharpen your pencil)の解答を求めてみる。
コード
Program.cs
using ConsoleApp1;
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;
// }
done = Console.ReadKey(true).KeyChar.ToString().ToUpper() switch
{
"G" => GroupComicsByPrice(),
"R" => GetReviews(),
_ => true,
};
}
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;
}
static bool GetReviews()
{
var reviews = ComicAnalyzer.GetReviews(Comic.Catalog, Comic.Reviews);
foreach (var review in reviews)
{
Console.WriteLine(review);
}
return false;
}
Comic.cs
using System;
namespace ConsoleApp1;
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},
};
}
ComicAnalyzer.cs
using System;
namespace ConsoleApp1;
public 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;
return catalog
.OrderBy(comic => prices[comic.Issue])
.GroupBy(CalculatePriceRange);
}
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}";
return catalog
.OrderBy(comic => comic.Issue)
.Join(reviews,
(comic) => comic.Issue,
(review) => review.Issue,
(comic, review) => $"{review.Critic} rated #{comic.Issue} '{comic.Name}' {review.Score:0.00}");
}
}
Critics.cs
namespace ConsoleApp1;
public enum Critics
{
MuddyCritic,
RottenTornadoes,
}
PriceRange.cs
namespace ConsoleApp1;
public enum PriceRange
{
Cheap,
Expensive,
}
Review.cs
using System;
namespace ConsoleApp1;
public class Review
{
public int Issue { get; set; }
public Critics Critic { get; set; }
public double Score { get; set; }
public Review()
{
}
}
入出力結果(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
%