時間帯重複チェック(応用編)にPythonで回答
応用編(お題:時間帯重複チェック(応用編) - No Programming, No Life)が掲載されていたので挑戦。
基本的な方針としては、期間を表現するクラスを定義する。あとはどうにかする。
実装後の感想としては、期間のコレクションクラスを定義したほうが綺麗にできそう。テストコードを分けたほうが読みやすくなりそう。
とりあえずテストコードだけでも書いておけば、作業を中断してもどこができてないかすぐに分かるので便利。
# -*- coding: utf-8 -*- # http://d.hatena.ne.jp/fumokmm/20110326/1301146382 # http://d.hatena.ne.jp/fumokmm/20110329/1301403400 import datetime import unittest class TimeDuplecationCheck2TestCase(unittest.TestCase): def testExample1(self): result = timeDuplicationCheck2((12, 0, 13, 0), (10, 0, 12, 15)) self.assertEquals(1, len(result)) self.assertEquals((12, 0, 12, 15), result[0]) def testExample2(self): result = timeDuplicationCheck2((16, 0, 23, 0), (9, 0, 17, 0), (5, 0, 10, 30)) self.assertEquals(2, len(result)) self.assertEquals((9, 0, 10, 30), result[0]) self.assertEquals((16, 0, 17, 0), result[1]) def testExample3(self): result = timeDuplicationCheck2((12, 0, 23, 0), (13, 0, 14, 0), (15, 0, 16, 0), (17, 0, 18, 0), (19, 0, 20, 0), (21, 0, 22, 0)) self.assertEquals(5, len(result)) self.assertEquals((13, 0, 14, 0), result[0]) self.assertEquals((15, 0, 16, 0), result[1]) self.assertEquals((17, 0, 18, 0), result[2]) self.assertEquals((19, 0, 20, 0), result[3]) self.assertEquals((21, 0, 22, 0), result[4]) def testExample4(self): result = timeDuplicationCheck2((10, 0, 12, 0), (11, 0, 11, 30), (10, 30, 11, 15)) self.assertEquals(1, len(result)) self.assertEquals((10, 30, 11, 30), result[0]) def testExample5(self): result = timeDuplicationCheck2((9, 0, 17, 0), (19, 0, 21, 0)) self.assertEquals(0, len(result)) def testValueError(self): self.assertRaises(ValueError, timeDuplicationCheck2, None) self.assertRaises(ValueError, timeDuplicationCheck2, (0, 0, 0, 0)) def timeDuplicationCheck2(*args): if 1 == len(args): raise ValueError result = [] for tuple1 in args[:-1]: period1 = Period(tuple1) for tuple2 in args[args.index(tuple1) + 1:]: period2 = Period(tuple2) if period1.isDuplicated(period2): result.append(period1.duplicatedPeriod(period2)) else: pass temp = [] for period in result: if len(temp) == 0: temp.append(period) elif temp[-1].isDuplicated(period): temp[-1] = temp[-1] + period else: temp.append(period) result = temp return sorted([p.asTuple() for p in result]) class TimeDuplecationCheckTestCase(unittest.TestCase): def testTimeDuplicationCheck(self): self.assertRaises(ValueError, timeDuplicationCheck, (-1, 0, 0, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (25, 0, 0, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, -1, 0, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 60, 0, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (24, 1, 0, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, -1, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 25, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, -1), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 60), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 24, 1), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (-1, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (25, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, -1, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 60, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (24, 1, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 0, -1, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 0, 25, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 0, 0, -1)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 0, 0, 60)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 0, 24, 1)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 1, 0, 0), (0, 0, 0, 0)) self.assertRaises(ValueError, timeDuplicationCheck, (0, 0, 0, 0), (0, 1, 0, 0)) self.assertFalse(timeDuplicationCheck((0, 0, 24, 0), (24, 0, 24, 0))) self.assertTrue(timeDuplicationCheck((0, 0, 24, 0), (0, 1, 23, 59))) self.assertFalse(timeDuplicationCheck((1, 0, 5, 30), (9, 0, 23, 0))) self.assertFalse(timeDuplicationCheck((1, 0, 2, 0), (2, 0, 3, 0))) self.assertTrue(timeDuplicationCheck((1, 0, 2, 1), (1, 59, 3, 0))) return def timeDuplicationCheck(period1, period2): period1 = Period(period1) period2 = Period(period2) return period1.isDuplicated(period2) class PeriodTestCase(unittest.TestCase): def setUp(self): self._allday = Period((0, 0, 24, 0)) def testInit(self): self.assertRaises(ValueError, Period, None) def testEq(self): self.assertEquals(self._allday, Period((0, 0, 24, 0))) self.assertEquals(Period((9, 0, 18, 0)), Period((9, 0, 18, 0))) self.assertNotEqual(self._allday, 0) self.assertNotEqual(self._allday, None) def testAdd(self): self.assertEquals(None, Period((0, 0, 12, 0)) + Period((12, 0, 24, 0))) self.assertEquals(Period((0, 0, 24, 0)), Period((0, 0, 12, 1)) + Period((12, 0, 24, 0))) def testDuplicatedPeriod(self): self.assertEquals(Period((9, 0, 12, 0)), self._allday.duplicatedPeriod(Period((9, 0, 12, 0)))) def testAsTuple(self): self.assertEquals((0, 0, 24, 0), self._allday.asTuple()) class Period(object): def __init__(self, period): if not isinstance(period, tuple): raise ValueError if not 4 == len(period): raise ValueError for value in period: if not isinstance(value, int): raise ValueError if not 0 <= period[0] <= 24: raise ValueError if not 0 <= period[1] <= 59: raise ValueError if not 0 <= period[2] <= 24: raise ValueError if not 0 <= period[3] <= 59: raise ValueError if 24 == period[0] and not 0 == period[1]: raise ValueError if 24 == period[2] and not 0 == period[3]: raise ValueError self._begin = createTime(period[0], period[1]) self._end = createTime(period[2], period[3]) if self._end < self._begin: raise ValueError def isDuplicated(self, other): return not None == self.duplicatedPeriod(other) def duplicatedPeriod(self, other): if not isinstance(other, Period): raise ValueError result = Period((0, 0, 0, 0)) if self._end <= other._begin or other._end <= self._begin: return None if other._begin < self._begin: result._begin = self._begin else: result._begin = other._begin if self._end < other._end: result._end = self._end else: result._end = other._end return result def __eq__(self, other): if None == other: return False if isinstance(other, Period): return self._begin == other._begin and self._end == other._end return False def __add__(self, other): if not self.isDuplicated(other): return None result = Period((0, 0, 0, 0)) if self._begin < other._begin: result._begin = self._begin else: result._begin = other._begin if self._end < other._end: result._end = other._end else: result._end = self._end return result def asTuple(self): tomorrow = datetime.datetime.today() + datetime.timedelta(days=1) tomorrow = datetime.datetime(tomorrow.year, tomorrow.month, tomorrow.day) result = [0, 0, 0, 0] if self._begin == tomorrow: result[0] = 24 result[1] = 0 else: result[0] = self._begin.hour result[1] = self._begin.minute if self._end == tomorrow: result[2] = 24 result[3] = 0 else: result[2] = self._end.hour result[3] = self._end.minute return tuple(result) def createTime(hour, minute): today = datetime.datetime.today() if hour == 24 and minute == 0: tomorrow = today + datetime.timedelta(days=1) return datetime.datetime(tomorrow.year, tomorrow.month, tomorrow.day, 0, 0) return datetime.datetime(today.year, today.month, today.day, hour, minute) def main(): unittest.main() if __name__ == '__main__': main()