[R] 프로그램 흐름제어 (3) - 기본 문법 활용하기

[R] 프로그램 흐름제어 (3) - 기본 문법 활용하기

if, while, for 문은 각각의 블록({}) 안에 같은 종류의 구문 혹은 다른 종류의 구문을 포함할 수 있습니다.

#01. 자주 사용되는 문법 패턴

자주 사용되는 문법의 중첩 패턴은 아래와 같다.

  • if - if
  • for - if
  • for - for

1) 중첩 조건문

하나의 조건을 좀 더 세분화 하여 판별하고자 할 경우 사용한다.

point <- 78

if (point > 70) {
    print ("패스입니다.")

    if (point > 90) {
        print("A입니다.")
    } else if (point > 80) {
        print("B입니다.")
    } else {
        print("C입니다.")
    }
} else {
    print("패스하지 못했습니다.")
}

💻 출력결과

[1] "패스입니다."
[1] "C입니다."

2) 조건문을 포함하는 반복문

매 반복 수행마다 조건을 판별

주로 반복되는 index값에 대한 조건을 판별하고자 하는 경우 사용한다.

x <- 0
y <- 0

# -> 1~10까지 반복 수행
for (i in seq(1, 10)) {
    if (i %% 2 == 0) {  # 어떤 수를 2로 나눈 나머지가 0이면 짝수
        print( sprintf("%d(은)는 짝수", i) )
        x <- x + i
    } else {            # 그렇지 않으면 홀수
        print( sprintf("%d(은)는 홀수", i) )
        y <- y + i
    }
}
print( sprintf("1~10까지 짝수들의 합: %d", x) )
print( sprintf("1~10까지 홀수들의 합: %d", y) )

💻 출력결과

[1] "1(은)는 홀수"
[1] "2(은)는 짝수"
[1] "3(은)는 홀수"
[1] "4(은)는 짝수"
[1] "5(은)는 홀수"
[1] "6(은)는 짝수"
[1] "7(은)는 홀수"
[1] "8(은)는 짝수"
[1] "9(은)는 홀수"
[1] "10(은)는 짝수"
[1] "1~10까지 짝수들의 합: 30"
[1] "1~10까지 홀수들의 합: 25"

3) 중첩 반복문

바깥의 반복문이 1회 수행되는 동안 안쪽의 반복문이 매번 처음부터 리셋되어 수행된다.

2중 반복문에서 바깥의 반복은 을 담당. 안쪽의 반복은 을 담당한다.

# 출력에 사용할 문장 형식
tpl = "%d x %d = %d"

# i의 변화범위 2부터 9까지
for (i in seq(2, 9)) {
    # i가 1 증가하는 동안 j의 값이 매번 1~9까지 새로 시작
    for (j in seq(1, 9)) {
        k <- i * j
        print( sprintf(tpl, i, j, k) )
    }

    if (i < 9) {
        print("---------------------")
    }
}

💻 출력결과

[1] "2 x 1 = 2"
[1] "2 x 2 = 4"
[1] "2 x 3 = 6"
[1] "2 x 4 = 8"
[1] "2 x 5 = 10"
[1] "2 x 6 = 12"
[1] "2 x 7 = 14"
[1] "2 x 8 = 16"
[1] "2 x 9 = 18"
[1] "---------------------"
[1] "3 x 1 = 3"
[1] "3 x 2 = 6"
[1] "3 x 3 = 9"
[1] "3 x 4 = 12"
[1] "3 x 5 = 15"
[1] "3 x 6 = 18"
... 생략 ...
[1] "8 x 8 = 64"
[1] "8 x 9 = 72"
[1] "---------------------"
[1] "9 x 1 = 9"
[1] "9 x 2 = 18"
[1] "9 x 3 = 27"
[1] "9 x 4 = 36"
[1] "9 x 5 = 45"
[1] "9 x 6 = 54"
[1] "9 x 7 = 63"
[1] "9 x 8 = 72"
[1] "9 x 9 = 81"

#02. 반복문 안에서의 흐름 제어

  • 반복을 몇 번 수행해야 하는지 판단할 수 없는 경우 무한루프 형태로 지정하고 특정 조건이 충족되는지에 따라 반복의 중단 여부를 결정한다.
  • 반복문의 흐름제어 기능을 갖는 키워드
    • next: 조건식으로 강제 이동
    • break: 현재 반복문을 강제로 종료하고 블록을 빠져 나간다.

1) while문을 사용한 무한루프 패턴

반드시 반복을 종료할 조건을 명시해야 한다.

y <- 0
while (TRUE) {       # 무조건 반복. 종료되지 않는다 (무한루프)
    y <- y + 1

    if (y %% 2 == 0) {
        next        # 조건식으로 강제 이동
    }

    if (y > 10) {
        break       # 반복문을 강제로 종료
    }

    print(sprintf("Hello World (%d)", y))
}

💻 출력결과

[1] "Hello World (1)"
[1] "Hello World (3)"
[1] "Hello World (5)"
[1] "Hello World (7)"
[1] "Hello World (9)"

2) repeat문

  • 반복의 조건이나 범위를 설정하지 않고 무조건 무한루프로 진행되는 반복문.
  • 반드시 특정 상황이 발생했을 때 break를 적용하여 중지시켜야 한다.

while 무한루프를 repeat문으로 변경

y <- 0
repeat {       # 무조건 반복. 종료되지 않는다 (무한루프)
    y <- y + 1

    if (y %% 2 == 0) {
        next        # 조건식으로 강제 이동
    }

    if (y > 10) {
        break       # 반복문을 강제로 종료
    }

    print(sprintf("Hello World (%d)", y))
}

💻 출력결과

[1] "Hello World (1)"
[1] "Hello World (3)"
[1] "Hello World (5)"
[1] "Hello World (7)"
[1] "Hello World (9)"

repeat문 사용하기

y <- 0
repeat {            # 무조건 반복. 종료되지 않는다 (무한루프)
    y <- y + 1

    if (y %% 2 == 0) {
        next        # 조건식으로 강제 이동
    }

    if (y > 10) {
        break       # 반복문을 강제로 종료
    }

    print(sprintf("Hello World (%d)", y))
}

💻 출력결과

[1] "Hello World (1)"
[1] "Hello World (3)"
[1] "Hello World (5)"
[1] "Hello World (7)"
[1] "Hello World (9)"

#03. 자주 등장하는 문제 패턴

1) 별찍기

2중 반복문에서 바깥의 반복이 수행되는 동안 내부의 반복문이 수행할 범위를 동적으로 결정할 수 있는가를 확인하는 문제

  • 순차 출력
for (i in seq(0, 4)) {        # 총 5행이라는 의미
    star <- ""                # 매 반복 수행시마다 star를 빈 문장으로 reset

    for (j in seq(0, i)) {    # 각 행마다 출력될 열의 수를 결정
        # paste0(a, b) 는 a와 b를 공백 없이 결합하여 반환함.
        star <- paste0(star, "*")
    }

    print(star)
}

💻 출력결과

[1] "*"
[1] "**"
[1] "***"
[1] "****"
[1] "*****"
  • 역순출력
for (i in seq(0, 4)) {
    star <- ""

    for (j in seq(i, 4)) {
        star <- paste0(star, "*")
    }

    print(star)
}
[1] "*****"
[1] "****"
[1] "***"
[1] "**"
[1] "*"

💻 출력결과

2) 백터의 역순 배치

백터를 역순으로 재배치 하기 위해서는 전체 길이의 반만큼만 반복을 수행해야 한다.

이 때 백터의 길이가 홀수인 경우 가운데 원소는 위치 변경이 필요 없으므로 나눗셈의 나머지를 버리고 정수부분의 몫만 취한다.

반복을 수행하면서 백터의 현재 위치와 반대쪽에 위치한 원소의 위치를 구해 서로 맞바꾸는 로직을 구현해야 한다.

# 원본 백터
my_vector <- c(5, 3, 7, 1, 9)
my_vector

# 백터의 길이 --> 5
size <- length(my_vector)

# 백터의 길이를 2로 나눈 정수 부분의 몫 --> 2
half <- size %/% 2

# 백터의 반 만큼만 반복 수행 --> 1부터 2까지
for (i in seq(1, half)) {
    # i번째 항목의 반대쪽에 위치한 원소의 인덱스를 구한다.
    p <- size - i + 1

    print( sprintf("i=%d, p=%d / my_vector[i]=%d, my_vector[p]=%d", i, p, my_vector[i], my_vector[p]) )

    # i번째 항목과 p번째 항목을 맞교환
    x <- my_vector[i]
    my_vector[i] <- my_vector[p]
    my_vector[p] <- x
}

# 결과출력
my_vector

💻 출력결과

5  3  7  1  9
[1] "i=1, p=5 / my_vector[i]=5, my_vector[p]=9"
[1] "i=2, p=4 / my_vector[i]=3, my_vector[p]=1"
9  1  7  3  5

3) 백터의 정렬

/images/posts/2022/1211/sort.png

# 원본 백터
my_vector <- c(5, 3, 7, 1, 9)
# 백터의 길이 --> 5
size <- length(my_vector)

# 처음부터 뒤에서 두 번째것 까지만 반복
for (i in seq(1, size-1)) {
    # i번째 다음부터 끝까지 반복
    for (j in seq(i+1, size)) {
        if (my_vector[i] > my_vector[j]) {
            # i번째 원소와 j번째 원소의 값을 맞바꾼다.
            x <- my_vector[i]
            my_vector[i] <- my_vector[j]
            my_vector[j] <- x
        }
    }
}

my_vector

💻 출력결과

[1] 1, 3, 5, 7, 9

4) for 반복문을 활용한 출력

for 반복문을 실행하여 아래와 같은 결과를 출력하시오.

6 6 6 6 6
5 5 5
4
3
2 2 2
1 1 1 1 1
line <- 6
count <- 5
level <- -2

for (i in seq(1, line)) {
    value <- line-i+1
    
    for (j in seq(1, count)) {
        cat(value)
    }
    cat("\n")
    
    count <- count + level
    if (count < 0) { count <- count * -1 }
    if (i+1 > line/2) { level <- 2 }
}

5) 위 (4)번의 예제를 while문을 활용하여 출력하시오.

line <- 6
count <- 5
level <- -2
i <- 1

while (i <= line) {
    value <- line-i+1
    
    j <- 1
    while (j <= count) {
        cat(value)
        j <- j+1
    }
    cat("\n")
    
    count <- count + level
    if (count < 0) { count <- count * -1 }
    if (i+1 > line/2) { level <- 2 }
    
    i <- i+1
}

6) 위 (5)번의 예제를 repeat문을 활용하여 출력하시오.

line <- 6
count <- 5
level <- -2
i <- 1

repeat {
    value <- line-i+1
    j <- 1
    
    repeat {
        cat(value)
        j <- j+1
        if (j > count) { break }
    }
    cat("\n")
    
    count <- count + level
    
    if (count < 0) { count <- count * -1 }
    if (i+1 > line/2) { level <- 2 }
    
    i <- i+1
    
    if (i > line) { break }
}
호쌤(이광호)'s Picture

About 호쌤(이광호)

메가스터디IT아카데미에서 Java, Spring, Python, Frontend 등을 강의하는 IT 전문 강사이자 프리렌서 개발자 입니다.
https://www.youtube.com/@hossam-codingclub

Seoul, Korea http://www.hossam.kr