흐름 제어: 조건문과 반복문(루프) 활용

요약

  • 조건문 활용
    • if문: 불리언 값을 이용하여 조건을 제시하는 방법
  • 반복문(루프) 활용

    • while 반복문(루프): 특정 조건이 만족되는 동안 동일한 과정을 반복하는 방법

    • for 반복문(루프): 특정 구간 내에서 동일한 과정을 반복하는 방법.

      • range 함수의 활용

최종 목표

  • 두 정수의 최대공약수를 구하는 함수: gcd()

    gcd(6, 8) = 2
    gcd(14, 21) = 3
  • 자연수 n이 주어졌을 때, 1부터 n까지의 자연수 중에서 3의 배수이거나 숫자 3을 포함하는 숫자들의 합을 구하는 함수 sum_of_3s() 구현하기:

    sum_of_3s(10) = 3 + 6 + 9
    sum_of_3s(15) = 3 + 6 + 9 + 12 + 13 + 15

조건문

어떤 일은 특정 조건 하에서만 할 수 있는 경우가 있다.

예를 들어, 숫자 k가 3의 배수이거나 3으로 끝나는 경우에만 그 값을 다른 값에 더하라고 할 수 있다.

위 문장을 코드로 나타내려면 아래 요소들이 필요하다.

  • 이런저런 경우에만 무엇무엇을 해라.
  • 숫자 k가 3의 배수이다.
  • 숫자 k가 숫자 3으로 끝난다.
  • "이런저런 경우에만 무엇, 무엇을 해라"는 if문으로 나타낸다.
    if 이런저런:
       무엇
       무엇
  • "숫자 k가 3의 배수이다"는 아래 수식으로 표현된다.
    k % 3 == 0
  • "숫자 k가 숫자 3으로 끝난다"는 좀 더 어렵지만, 앞서 배운 문자열 메소드를 활용하면 된다.
    str(k).endswith('3')

여기서 str() 함수는 숫자를 문자열로 형변환 시키는 함수이다. int() 또는 float() 함수와 반대의 일을 한다.

예제

두 개의 숫자 k, m이 주어졌을 때, 만약 m이 3의 배수이거나 3으로 끝나는 숫자일 경우에만 k와 m을 더하는 함수 sum_if_3()를 구현하라.

견본답안:

In [1]:
def sum_if_3(k, m):
    if (m % 3 == 0) or (str(m).endswith('3')):
        return k + m
    else:
        return k

주의: else문은 if문에서 다루는 경우가 성립하지 않을 때 무슨 일을 해야할지를 정한다.

In [2]:
sum_if_3(5, 18)
Out[2]:
23
In [3]:
sum_if_3(4, 7)
Out[3]:
4

예제

두 개의 숫자 k, m이 주어졌을 때, 만약 m이 3의 배수이거나 숫자 3을 포함하는 경우에만 k와 m을 더하는 함수 sum_if_3s()를 구현하라.

이 문제를 풀기 위해서는 문자열에 특정 문자열이 부분문자열로 포함되어 있는지를 판단해야 하는데 아래 예제와 같이 in 함수를 이용할 수 있다.

In [4]:
if 'bc' in 'abcde':
    print("'bc'가 'abcde'의 부분문자열이다.")
'bc'가 'abcde'의 부분문자열이다.

견본답안:

In [5]:
def sum_if_3s(k, m):
    if (m % 3 == 0) or ('3' in str(m)):
        return k + m
    else:
        return k
In [6]:
sum_if_3s(2, 31)
Out[6]:
33
In [7]:
sum_if_3s(3, 15)
Out[7]:
18
In [8]:
sum_if_3s(13, 28)
Out[8]:
13

중첩 조건문과 일반화된 조건문

if ... else ... 문은 두 가지 경우를 처리할 때 사용한다.

반면에, 예를 들어, 크거나, 같거나, 작거나 등 세 가지 이상의 경우를 처리하려면 if ... else ...문을 중첩해서 사용하거나 if ... elif ... elif ... else ... 처럼 다중 조건문을 사용할 수 있다.

  • 중첩 조건문(중첩 if문) 활용 예제
In [9]:
num1 = 5
num2 = 10

if num1 < num2:
    print("num1이 num2 보다 작다.")
else:
    if num1 == num2:
        print("num1이 num2와 같다.")
    else:
        print("num1이 num2 보다 크다.")
num1이 num2 보다 작다.
  • 다중 조건문(다중 if문) 활용 예제
In [10]:
num1 = 5
num2 = 10

if num1 < num2:
    print("num1이 num2 보다 작다.")
elif num1 == num2:
    print("num1이 num2와 같다.")
else:
    print("num1이 num2 보다 크다.")
num1이 num2 보다 작다.

주의: if문의 중첩 정도는 임의로 복잡해질 수 있다. 따라서 가능하면 일반화된 조건문을 사용하면 다루기가 보다 쉬워진다.

반복문(루프)

반복문(루프)은 동일한 코드를 반복해서 실행시킬 때 사용한다. 루프를 만들기 위해 for문과 while문을 사용한다.

  • for 반복문: 반복을 몇 번 할지 미리 알 수 있는 경우 사용
  • while 반복문: 특정 조건이 만족되는 동안 반복하고자 할 경우

여기서는 먼저 while 반복문을 살펴보고 이후에 for 반복문을 살펴본다.

while 반복문

while 반복문은 항상 아래 모양을 갖는다:

while 조건:
    본문코드1
    본문코드2
    ...

조건이 참이 되는 동안 본문코드들이 실행된다.

예제

정수들을 나누어 몫을 구하는 코드를 작성해보자. 몫을 어떻게 구현할까?

  • 먼저 몫이 어떤 의미인가를 알아야 한다.
  • 그 다음에 그 의미를 구현하는 코드를 작성한다.

어떤 정수 a를 다른 정수 b로 나누었을 때의 몫은 a에서 b를 몇 번 뺄 수 있는가와 동일한 의미를 갖는다. 즉, a에서 b를 반복해서 빼주는 과정이 필요하고 이 과정을 음수가 되지 않을 때까지만 반복해야 한다.

예를 들어 43을 7로 나누었을 때의 몫은 다음과 같이 구할 수 있다.

In [11]:
number = 43
divisor = 7
answer = 0

# While 루프
while number > 0:
    number = number - divisor
    # 음수가 아니라면 빼주는 횟수를 1회 늘린다.
    if number > 0:
        answer += 1

# 이제 answer를 출력하면 된다.
print('몫은', answer, '이다')
몫은 6 이다

'while' 루프를 작성할 때 조건문이 언젠가는 만족되지 않아서 더 이상 루프가 돌지 않도록 코드를 작성하는 것이 가장 중요하다.

연습

두 정수의 최대공약수(gcd)를 리턴하는 함수를 구현하라.

힌트: 유클리드 호제법을 활용하라. 아래 사이트 참조: http://tibyte.kr/224

견본답안:

In [12]:
def gcd(a, b):
    if a < b:
        # 이 경우에는 a와 b의 값을 서로 바꾼다.
        a, b = b, a
    while b != 0:
        a, b = b, a % b
    return a

주의: 파이썬에서 두 변수에 할당된 값을 맞교환 하는 방법이 매우 간단하다. 하지만 C 또는 자바에서는 다르게 처리해야 한다. 예를 들어, 아래와 같은 방식을 이용할 수 있다.

int a = 3
int b = 5
int temp

temp = a
a = b
b = temp
In [13]:
gcd(6, 8)
Out[13]:
2
In [14]:
gcd(14, 21)
Out[14]:
7

for 루프

while 반복문과는 달리 몇 번 반복되어야 하는지를 아는 경우 for 반복문을 사용할 수 있으며, 아래 형식을 따른다.

for 항목변수 in 컬렉션 자료형 :
        코드1
        코드2
        ...

컬렉션 자료형: 리스트, 튜플, 문자열, 어레이 등 여러 개의 값을 동시에 다룰 수 있는 자료형을 의미하며, 다음 시간에 보다 자세히 다룬다.

여기서는 문자열과 range() 함수를 이용하여 for 반복문을 사용하는 법을 익힌다.

문자열과 for

예제

아래 코드는 문자열에 포함된 문자 각각을 출력한다.

In [15]:
for char in "adam":
    print(char)
a
d
a
m

연습

문자열에 있는 소문자 a를 대문자 A로 변경하여 새로운 문자열을 생성하는 코드를 작성하라.

예를 들어, "aardvarks"를 이용하여 "AArdvArks"를 생성하는 코드를 작성하라.

견본답안1:

In [16]:
a_word = 'aardvarks'
new_word = ''
for char in a_word:
    if char == 'a':
        new_word = new_word + 'A'
    else:
        new_word = new_word + char

print(new_word)
AArdvArks

연습

아래 문자열

' n o r t h w e s t e r n'

을 이용하여 아래 문자열을 생성하는 코드를 구현하라:

'Northwestern'

In [17]:
a_word = ' n o r t h w e s t e r n'

temp_word = ''
for char in a_word:
    if char != ' ':
        temp_word = temp_word + char
        
new_word = temp_word.title()

print(new_word)
Northwestern

range() 함수와 for

range() 함수는 일정한 규칙에 따라 나열된 수열을 생성한다.

In [18]:
a_range = range(10)
print(a_range)
range(0, 10)

range() 함수의 리턴값의 자료형은 리스트이다.

주의: 파이썬3에서 range() 함수의 리턴값은 range라는 자료형이다. 리스트와 거의 비슷하지만 용도가 좀 다르다는 정도만 기억하고 넘어가도 좋다.

In [19]:
type(a_range)
Out[19]:
range

range() 함수는 인자를 최대 세 개까지 받을 수 있다. 각 인자들의 역할은 슬라이싱에 사용되는 세 개의 인자들의 역할과 동일하다.

  • range([start,] stop [, step])
  • start의 경우 주어지지 않으면 0을 기본값으로 갖는다.
  • step의 경우 주어지지 않으면 1을 기본값으로 갖느다.
In [20]:
a_range_1 = range(3, 10)
a_range_1
Out[20]:
range(3, 10)
In [21]:
a_range_2 = range(3, 10, 2)
a_range_2
Out[21]:
range(3, 10, 2)

range 함수는 for문에서 유용하게 활용된다.

In [22]:
for i in range(6):
    print(i,"의 제곱은", i ** 2, "이다.")
0 의 제곱은 0 이다.
1 의 제곱은 1 이다.
2 의 제곱은 4 이다.
3 의 제곱은 9 이다.
4 의 제곱은 16 이다.
5 의 제곱은 25 이다.
In [23]:
for i in range(0, 6, 2):
    print(i,"의 제곱은", i ** 2, "이다.")
0 의 제곱은 0 이다.
2 의 제곱은 4 이다.
4 의 제곱은 16 이다.

단순한 카운트 역할을 수행하는 용도로 range함수를 활용할 수도 있다. 즉, 어떤 일을 특정 횟수만큼 반복하고자 할 때 사용한다.

In [24]:
for i in range(5):
    print("다섯 번 출력합니다.")
다섯 번 출력합니다.
다섯 번 출력합니다.
다섯 번 출력합니다.
다섯 번 출력합니다.
다섯 번 출력합니다.

range() 함수와 문자열 인덱싱을 활용하면 문자열에 대해 for문을 직접 활용하는 것과 동일한 일을 할 수 있다.

예를 들어, 문자열의 길이와 range() 함수를 다음처럼 활용할 수 있다.

In [25]:
a_word = 'hamster'

for i in range(7):
    print(a_word[i])
h
a
m
s
t
e
r
In [26]:
a_word = 'hamster'

for i in a_word:
    print(i)
h
a
m
s
t
e
r

주의: 문자열의 길이가 range() 함수에 사용되는 인자보다 작으면 오류가 발생한다. 이유는 문자열의 길이보다 긴 인덱스가 사용되기 때문이다.

In [27]:
for i in range(8):
    print(a_word[i])
h
a
m
s
t
e
r
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-27-34a36308584e> in <module>
      1 for i in range(8):
----> 2     print(a_word[i])

IndexError: string index out of range

이제 아래 문제를 해결할 수 있다.

연습

자연수 n이 주어졌을 때, 1부터 n까지의 자연수 중에서 3의 배수이거나 숫자 3을 포함하는 숫자들의 합을 구하는 함수 sum_of_3s() 구현하기:

sum_of_3s(10) = 3 + 6 + 9 = 18
sum_of_3s(15) = 3 + 6 + 9 + 12 + 13 + 15 = 58

견본답안:

In [28]:
def sum_of_3s(n):
    sum = 0
    for i in range(1, n+1):
        if i % 3 == 0:
            sum = sum + i
        elif '3' in str(i):
            sum = sum + i
    return sum
In [29]:
sum_of_3s(10)
Out[29]:
18
In [30]:
sum_of_3s(15)
Out[30]:
58

연습

두 정수의 최대공약수(gcd)를 리턴하는 함수를 구현하라.

견본답안:

In [31]:
def gcd(a, b):
    if a < b :
        a, b = b, a
    while b != 0:
        a, b = b, a % b
    return a
In [32]:
gcd(10, 25)
Out[32]:
5
In [33]:
gcd(124, 36)
Out[33]:
4

연습

두 정수의 최소공배수(lcm)를 리턴하는 함수를 구현하라.

견본답안:

In [34]:
def lcm(a, b):
    g = gcd(a, b)
    c = a/g
    return c*b
In [35]:
lcm(10, 25)
Out[35]:
50.0
In [36]:
lcm(124, 36)
Out[36]:
1116.0

연습

아래 노래 가사를 활용하는 문제이다.

In [37]:
song = "When you are smiling, the whole world smiles with you"

(1) 위 문자열에서 a가 등장하는 횟수를 구하는 코드를 작성하라.

견본답안:

In [38]:
count_a = 0
for word in song:
    if word == 'a':
        count_a += 1

print(count_a)
1

(2) 위 문자열에서 대소문자 구별없이 w가 등장하는 횟수를 구하는 코드를 작성하라.

견본답안:

In [39]:
count_w = 0
for word in song.lower():
    if word == 'w':
        count_w += 1

print(count_w)
4

(3) 다음 문자열을 이용하여, whnyrsmlngthwhlwrldsmlswthyu를 생성하는 코드를 작성하라. (힌트: 모음(aeiou)와 공백 제거)

견본답안:

In [40]:
new_song = ''
for word in song.lower():
    if word not in 'aeiou, ':
        new_song += word

print(new_song)
whnyrsmlngthwhlwrldsmlswthy