How to Solve Problems
What is the first thing we should do to solve a problem like this one?(문제를 풀기위해 가장 우선되는게 무엇인가?)
- Make sure we under stand the problem. (일단 뭐가 문제인지 아는게 중요하다.)
- Search Google for the answer (연습할때가 아니라면 구글링을 해보는것도 좋다)
Understanding a (Computational) Problem(컴퓨팅적 문제 이하하기 - 뭐가문제이며 어떻게 풀지)
Given you birthday and the current date, calculate your age in days.
└──inputs └──outputs
Problem is defined by Possible inputs(어떤값이 들어가는지 확실하게 알아라) relationship between inputs --> ouputs(desired)
Solution : input => <procedure> => output
- What are the inputs? "Given your birthday and the current date, calculate your age in days."
- birthday, current day
- second date must not be beofre first date => Defensive Programming (check this in our code)
- How are inputs represented?
def days BetweeonDates(year1, month1, day1, years2, month2, day2)
- What are the ouputs? "... , calculate your age in days"
- return days between two input days
- Solve the problem!
Quiz : The Expected Output(to understand the relationship between the two inputs)
For each, give the expected output or undefined if there is no defined output.
daysBetweenDates(2012,12,7,2012,12,7) # => 0
daysBetweenDates(2012,12,7,2012,12,8) # => 1
daysBetweenDates(2012,12,8,2012,12,7) # => undefined
daysBetweenDates(2012,6,29,2013,6,29) # => 365
daysBetweenDates(2012,6,29,2013,6,31) # => undefined
Before solving the problem
- understand the inputs
- understand the ouputs
- understande the relationship - some examples
- Consider systematically how a human solves the problem
Algorithm "pseudo code"
Example : counting the number of days remaining1 in january
days = number of days in month1 - day1 # 31 - 24 = 7
month1 += 1 # 2월로 넘어간다
while month1 < month2:
days += number of days in month1
month1 += 1
days += days2
while year1 < year2:
days += days in year1
doesn't handle:
- input dates in smae month
- month2 < month1, years2 > years1
It's too complex we should try to find a simpler ways
Simple mechanical algorithm
days = 0
while date1 is before date2:
date1 = advance to next days # => nextDay
days += 1
return days
nextDay(year,month,day)
Define a simple nextDay
procedure, that assumes every month has 30 days.
### nexDay(2017,3,1) => 2017,3,2
### nexDay(2017,3,30) => 2017,4,1
#민우코드
def nextDay(year, month, day):
"""Warning: this version incorrectly assumes all month have 30 days!"""
if day < 30:
day += 1
else:
day = 1
if month < 12:
month += 1
else:
month = 1
year += 1
return year, month, day
#udacity
def nextDay(year, month, day):
if day < 30:
return year, month, day + 1
else:
if month < 12:
return year, month+1, 1
else:
return year + , 1, 1
# 내코드가 더 이해하기 쉬운걸?
dayBetweenDates
Define an (approximate2) daysBetweenDates
procedure that would produce the correct results given a correct nextDay procedure
#민우코드
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
days = 0
year,month,day = year1,month1,day1
while True:
if (year == year2) and (month == month2) and (day == day2): break
else:
year,month,day = nextDay(year,month,day)
days += 1
return days
#되게 기특한걸?
#year,month,day 변수를 만들 필요는 없지만, 난 원래 따로 저장해두는게 좋다.
#udacity
#helpercode 나는 이부분을 if/else로 이용하고 루프를 돌렸다.
def dateIsBefore(year1, month1, day1, year2, month2, day2):
"""Returns True if year1, month1, day1 are before year2, month2, day2"""
if year1 < year2: #년도가 작다면 더이상 볼필요가 없다.
return True
if year1 == year2:
if month1 < month2: #년도가 같으면 월이라도 작아야한다.
return True
if month1 == month2:
return day1 < day2 #년과 월이같으면 일이라도 작아야한다.
return False #다 아니면 이거 작은게 아니다. (같거나 크다)
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
days = 0
year,month,day = year1,month1,day1
while dateIsBefore(year1, month1, day1, year2, month2, day2):
year1,month1,day1 = nextDay(year,month,day)
days += 1
return days
#helpercode를 사용하면 아무래도 좀더 정확할것 같다. 내코드는 어느 날짜가 빠른지 확인이 안된다. 그냥 믿고 대입..
# => 앞에 대입하는 날짜가 큰경우에 0을 반환한다. 이건 문제다.
# 내코드 if/else 문에 else if로 이걸 넣는게 솔루션이 되지 않을까?
#udacity는 새로운 변수를 만들지 않았다. 이부분은 내코드가 더 좋다고 생각한다.
#왜냐면 새로운 변수를 만들어 사용하고 이전값을 보전하는게 유지보수하기 좋다고 생각하기 때문이다.
Add an assertion3 to daysBetweenDates
to give an assertion failure when the inputs are invalid4
#민우코드
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
"""Returns the number of days between year1/month1/day1
and year2/month2/day2. Assumes inputs are valid dates
in Gregorian calendar."""
# program defensively! Add an assertion if the input is not valid!
days = 0
year,month,day = year1,month1,day1
while True:
if dateIsBefore(year, month, day, year2, month2, day2):
year, month, day = nextDay(year, month, day)
days += 1
elif (year == year2) and (month == month2) and (day == day2):
return days
else:
assert not dateIsBefore(year2, month2, day2, year, month, day)
# 원래 내코드에 dateIsBefore()을 넣었다.
# 근데 이건 한번만 확인하면 되는건데 매번 확인하는것 같아서 별로다.
#udacity
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
# program defensively! Add an assertion if the input is not valid!
assert not dateIsBefore(year2, month2, day2, year1, month1, day1)
days = 0
while dateIsBefore(year1, month1, day1, year2, month2, day2):
year1, month1, day1 = nextDay(year1, month1, day1)
days += 1
return days
# assert를 이렇게 쓰는거구나! 레일즈의 before_action 같은느낌!
# assert 뒤에 true가 나오면 작동하는건가? 근데 여전히 같은 날에 대한 대응은 안되는것 같은데?
# => 대응 된다. 날짜가 같은경우에는 에러를 안밷는것 같은데 왜지? . 내코드에서 elif와 else를 합친게 저한줄..ㅠ
Finish daysBetweenDates
추가할 프로시저(procedure: 함수)
daysInMonth(year, month)
isLeapYear(year)
#민우코드
def isLeapYear(year):
if year%400 ==0:
return True
elif year%100 == 0:
return False
elif year%4 ==0:
return True
else:
return False
def daysInMonth(year,month):
days = [31,28,31,30,31,30,31,31,30,31,30,31]
if isLeapYear(year) and month==2:
return 29
else:
return days[month-1]
#udacity
def daysInMonth(year,month):
#1,3,5,7,8,10,12
if month == 1 or month == 3 or month == 5 or month == 7 \
or month == 8 or month == 10 or month == 12:
return 31
elif month == 2:
if isLeapYear(year):
return 29
else:
return 28
else:
return 30
# isLeapYear()은 내코드와 동일하다.
#내코드가 가독성이 좋은건 그냥 내꺼라서 그런가ㅋㅋㅋㅋㅋ
#유지보수용으로는 이 코드가 더 좋을것 같다.
nextDay에 추가
def nextDay(year, month, day):
if day < daysInMonth(year,month):
return year, month, day + 1
else:
if month == 12:
return year + 1, 1, 1
else:
return year, month + 1, 1
Test Case 추가
def test():
assert daysBetweenDates(2013, 1, 1, 2013, 1, 1) == 0
assert daysBetweenDates(2012, 2, 28, 2012, 3, 1) == 2
assert daysBetweenDates(2017, 5, 24, 2018, 7, 27) == 429
assert nextDay(2013, 1, 1) == ( 2013, 1, 2)
print "Test Finish"
test()
다시하니까 그렇게 많이 안어렵고 강의에서 잘알려준것 같다.
신난다~~~!
1. remain : 남아있다. 잔류하다. ↩
2. approximate : 근접한 ↩
3. assertion : 주장을 표명, 단언 ↩
4. valid/invalid : 유효한 / 유효하지 않은(무효인) ↩