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

요약

  • 조건문 활용
    • 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]:
# 좀 더 세련된 print 함수를 사용하고자 한다.
from __future__ import print_function

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 [1]:
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)


[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

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

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


In [19]:
type(a_range)


Out[19]:
list

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

  • range([start,] stop [, step])
  • start의 경우 주어지지 않으면 0을 기본값으로 갖는다.
  • step의 경우 주어지지 않으면 1을 기본값으로 갖느다.

In [20]:
a_range_1 = range(3, 10)
a_range_1


Out[20]:
[3, 4, 5, 6, 7, 8, 9]

In [21]:
a_range_2 = range(3, 10, 2)
a_range_2


Out[21]:
[3, 5, 7, 9]

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


In [22]:
from __future__ import print_function

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-b2a0345b7976> 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