using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { Console.WriteLine("Q1: " + new[] { new FromTo(12, 0, 13, 0), new FromTo(10, 0, 12, 15) }.Intersection().Normalize().Join(", ")); Console.WriteLine("Q2: " + new[] { new FromTo(16, 0, 23, 0), new FromTo(9, 0, 17, 0), new FromTo(5, 0, 10, 30) }.Intersection().Normalize().Join(", ")); Console.WriteLine("Q3: " + new[] { new FromTo(12, 0, 23, 0), new FromTo(13, 0, 14, 0), new FromTo(15, 0, 16, 0), new FromTo(17, 0, 18, 0), new FromTo(19, 0, 20, 0), new FromTo(21, 0, 22, 0) }.Intersection().Normalize().Join(", ")); Console.WriteLine("Q4: " + new[] { new FromTo(10, 0, 12, 0), new FromTo(11, 0, 11, 30), new FromTo(10, 30, 11, 15) }.Intersection().Normalize().Join(", ")); Console.WriteLine("Q5: " + new[] { new FromTo(9, 0, 17, 0), new FromTo(19, 0, 21, 0) }.Intersection().Normalize().Join(", ")); } } struct FromTo { public readonly TimeSpan From; public readonly TimeSpan To; public FromTo(TimeSpan from, TimeSpan to) { if (!Validate(from, to)) throw new ArgumentException(); this.From = from; this.To = to; } public FromTo(int fromHours, int fromMinutes, int toHours, int toMinutes) : this(Convert(fromHours, fromMinutes), Convert(toHours, toMinutes)) { } private static TimeSpan Convert(int hours, int minutes) { TimeSpan result = new TimeSpan(hours, minutes, 0); if (result.Hours != hours || result.Minutes != minutes) throw new ArgumentException(); return result; } private static bool Validate(TimeSpan from, TimeSpan to) { return (TimeSpan.Zero <= from && from <= to && to <= new TimeSpan(24, 0, 0)); } public bool IsEmpty { get { return this.From == this.To; } } public override string ToString() { return string.Format( "{0:00}:{1:00}-{2:00}:{3:00}", this.From.Hours, this.From.Minutes, this.To.Hours, this.To.Minutes); } } static class FromToEx { public static string Join(this IEnumerable source, string separator) { return string.Join(separator, source.Select(x => x.ToString()).ToArray()); } public static IEnumerable Normalize(this IEnumerable source) { var ordered = source.OrderBy(x => x.From); var prev = default(FromTo); foreach (var current in ordered) { if (prev.To <= current.From) { // prevとcurrentが重なっていない if (!prev.IsEmpty) yield return prev; prev = current; } else { // prevとcurrentが重なっているので、結合する var from = prev.From; var to = (prev.To < current.To) ? current.To : prev.To; prev = new FromTo(from, to); } } if (!prev.IsEmpty) { yield return prev; } } public static IEnumerable Intersection(this IEnumerable source) { var ordered = source.OrderBy(x => x.From); var prev = default(FromTo); foreach (var current in ordered) { if (prev.To <= current.From) { // prevとcurrentが重なっていない prev = current; } else { // prevとcurrentが重なっているので、重なっている部分を取り出す var from = current.From; var to = (prev.To < current.To) ? prev.To : current.To; yield return new FromTo(from, to); prev = (prev.To < current.To) ? current : prev; } } } }