while과 for 루프
while 루프
- 코틀린에는 while과 do-while 루프가 있고, 문법은 자바와 같다.
fun main(args: Array<String>) {
// while
var num = 3
while(num > 0) {
println("$num")
num -= 1
}
// do-while
num = 3
do {
println("$num")
num -= 1
} while(num > 0)
}
수에 대한 이터레이션: 범위와 수열
코틀린에서는 자바의 for 루프(초깃값, 증가 값, 최종 값) 형태가 아닌 for-each 루프와 유사한 범위(range)를 사용해서 이터레이션을 구현한다.
범위는 기본적으로 정수 등의 두 숫자 값으로 이뤄진 구간이며 ".." 연산자로 시작 값과 끝 값을 연결해서 범위를 만든다.
# python
for i in range(1, 100): # 1부터 99까지
print(i)
// kotlin
for (i in 1..100) { // 1부터 100까지
println(i)
}
파이썬과 형태는 비슷하지만 파이썬은 (두 번째 값 -1) 까지만 반복하는 반면, 코틀린의 범위는 두 번째 값이 항상 범위에 포함된다.
따라서 ".." 연산자는 항상 범위의 끝 값을 포함하기 때문에 끝 값을 포함하지 않기 위해서는 until을 사용해야 한다.
for (i in 1 until 100) { // 1부터 99까지, python의 for i in range(1, 100)과 같다
println(i)
}
간단하게 인자가 없는 when 을 사용해서 피즈버즈 게임을 작성해보자.
fun fizzBuzz(i: Int) = when {
i % 15 == 0 -> "FizzBuzz"
i % 3 == 0 -> "Fizz"
i % 5 == 0 -> "Buzz"
else -> "$i"
}
for (i in 1..100) { // 1부터 100까지 반복(..은 끝값 포함이기 때문에, 제외하고 싶으면 until 사용)
println(fizzBuzz(i))
}
만약 증가 값을 갖고 범위를 반복하고 싶으면 아래와 같이 step 키워드를 사용하면 된다.
for (i in 1..100 step 2) { // 1부터 100까지 2씩 증가하면서 반복
println(i)
}

만약 2씩 작아지는 step을 원해서 step -2를 작성한다면 아래와 같은 에러를 만날 것이다.
즉 step 다음에 오는 값은 무조건 정수여야 한다.

따라서 1에서 100까지 2씩 작아지는 반복을 구현하고 싶다면 downTo 키워드와 step 키워드를 같이 사용하면 된다.
(역방향 수열의 기본 증가 값은 -1이므로 step 키워드를 사용해 -2씩 증가하도록 한다.)
for (i in 100 downTo 1 step 2) { // 100부터 1까지 -2씩 증가하면서 반복
println(i)
}

맵에 대한 이터레이션
- 문자에 대한 2진 표현을 맵에 저장하고, 맵의 내용을 출력하는 프로그램을 작성해보자.
// kotlin
val binaryReps = TreeMap<Char, String>
for (c in "A".. "F") { // A부터 F까지의 문자의 범위를 사용해 반복한다.
binaryReps[c] = Integer.toBinaryString(c.toInt()) // c를 키로 c의 2진 표현을 맵에 넣는다.
}
for ((key, value) in binaryReps) { // 맵에 대해 반복한다.
print("$key = $value")
}

// java
public class Test {
public static void main(String[] args) {
Map<Character, String> map = new TreeMap<>();
for (char c : "ABCDEF".toCharArray()) {
map.put(c, Integer.toBinaryString((int) c));
}
for (Map.Entry<Character, String> entries : map.entrySet()) {
System.out.println(entries.getKey() + " = " + entries.getValue());
}
}
}
# python
import string
tree_map = dict()
for i in string.ascii_uppercase[:6]:
tree_map[i] = bin(ord(i))
for key, value in sorted(tree_map.items()):
print(key + " = " + value)
코틀린은 느낌상 자바의 문법을 파이토닉하게 풀어쓴듯한 느낌이 많이 든다.
코틀린에서는 ".." 연산자를 숫자 타입의 값뿐 아니라 문자 타입의 값에도 적용할 수 있다.
따라서 'A'..'F' 는 A부터 F에 이르는 모든 문자를 포함하는 범위를 만든다.
컬렉션과 인덱스 활용
파이썬에는 enumerate 함수가 있어서 컬렉션의 원소와 인덱스를 같이 활용할 수 있다.
따라서 별도의 인덱스로 사용하기 위한 i를 선언하고 루프에서 매번 그 변수를 증가시킬 필요가 없다.
아래의 예시를 보자.
# python
for index, element in enumerate([1,2,3,4,5]):
print(f"index = {index} element = {element}")
코틀린에서는 이와같은 기능을 withIndex() 메소드로 사용할 수 있다.
// kotlin
val list = arrayListOf("10", "11", "12")
for ((index, element) in list.withIndex()) {
println("$index: $element")
}
in으로 컬렉션이나 범위의 원소 검사
in 연산자를 사용해 어떤 값이 범위에 속하는지 검사할 수 있다.
반대로 !in을 사용하면 어떤 값이 범위에 속하지 않는지 검사할 수 있다.
아래의 예시를 보자.
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z' // 'a' <= c && c <= 'z' 로 변환된다.
fun isNotDigit(c: Char) = c !in '0'..'9' // 만약 '9'..'0'으로 작성하면 '9' <= c && c <= '0' 로 변환된다.
println(isLetter('t')) // true
println(isNotDigit("x")) // true
in과 !in 연산자는 when 식에서도 사용이 가능하다.
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "it's a digit"
in 'a'..'z' -> "it's a letter"
else -> "what is this?"
}
println(recognize('v')) // it's a digit
비교가 가능한 클래스라면(Comparable 인터페이스를 구현한 클래스라면) 그 클래스의 인스턴스 객체를 사용해 범위를 만들 수 있다.
println("Kotlin" in "Java".."Scala") // true
위의 코드는 "Java" <= "Kotlin" && "Kotlin" <= "Scala" 와 같다.
String에 있는 Comparable 구현이 두 문자열을 알파벳 순서로 비교하기 때문에 여기 있는 in 검사에서도
문자열을 알파벳 순서로 비교한다.
컬렉션에서도 마찬가지로 in 연산을 사용할 수 있다.
// kotlin
println("Kotlin" in setOf("Java", "Scala")) // false
println("Java" in setOf("Java", "Scala")) // true
위의 비교는 아래의 python 구현과 동일하다.
# python
print("Kotlin" in {"Java", "Scala"}) # False
print("Java" in {"Java", "Scala"}) # True
Comments