Kotlin (2) 콜렉션, 열거형, 분기

저번 시간에는 함수, 변수, 클래스 정의에 대하여 공부하였었다.

오늘은 그 함수와 변수를 더 다양하게 정의하는 방법이나, 목록으로 정의된 변수에 대해 일괄 처리하는 방법에 대해 공부하겠다.

이후에 나오는 코드들은 Kotlin Playground에서 직접 입력하고, 실행하며 학습하면 도움이 된다!

바로 본론으로 넘어가겠다.

Kotlin

☝ Collection

Collection은 우리가 알던 배열과 비슷한 종류의 것들을 모두 총칭하는 단어이다.

Collection의 정의는 “목록형 데이터를 처리하는 자료구조“를 뜻한다.

Kotlin에서는 Collection을 여러가지 방법으로 선언할 수 있다.

기본적으로 List, Set, Map의 세 가지가 있으며, 더욱 세세한 분류로 나눌 수도 있다.

모든 배열은 읽기/쓰기가 가능한 가변형mutable type과, 읽기/쓰기가 불가능한 불변형immutable type로 분류가 가능하다.

각각을 간단히 알아보고, 하위 주제에서 예시를 통해 다루겠다.

  1. List
    • 순서가 중요한 가변 크기의 배열을 의미한다.
      • listOf()로 선언 시 불변형
      • mutableListOf() 형으로 선언하여 가변형으로 선언 가능.
  2. Set
    • 순서가 없고, 중복을 허용하지 않음.
      • setOf()로 선언 시 불변형
      • mutableSetOf() 형으로 선언하여 가변형으로 선언 가능.
  3. Map
    • 데이터를 key-value 쌍 형식으로 저장한다.
    • key는 항상 유일함.
      • mapOf()로 선언 시 불변형
      • mutableMapOf() 형으로 선언하여 가변형으로 선언 가능.

정도가 될 것이다.

1.1 List

List의 가장 큰 특징은, 순서가 존재한다는 것이다.

Kotlin

fun main() {
	val weekDays = listOf("Sun","Mon","Tue","Wed","Thu","Fri","Sat")
    print(weekDays)
}

Result

[Sun, Mon, Tue, Wed, Thu, Fri, Sat]

이런 형식으로 불변형 List를 선언할 수 있다.

이런 식으로 List를 선언하면, weekDays의 변수형은 List<String>이 된다.

List는 순서가 존재하기 때문에, index를 이용해 값을 호출할 수 있다.

다른 언어들과 비슷하게 첫 번째 원소의 index는 0부터 시작한다.

Kotlin

fun main() {
	val weekDays: List<String> = listOf("Sun","Mon","Tue","Wed","Thu","Fri","Sat")
    print(weekDays[0]+", "+weekDays[5])
}

Result

Sun, Fri

불변형이 아닌, 가변형 List를 만들고 싶다면, listOf대신에 mutableListOf를 사용하면 된다.

이 때의 변수형 역시 List<String>이 아닌, MutableList<String>가 된다.

Kotlin

fun main() {
	var weekDays: MutableList<String> = mutableListOf("Sun", "Mon", "Tue", "Wed", "Thu")
    weekDays.add("Fri")
    weekDays.add("Sat")
    weekDays.add("Foo")
    println(weekDays)
    weekDays.remove("Foo")
    println(weekDays)
}

Result

[Sun, Mon, Tue, Wed, Thu, Fri, Sat, Foo]
[Sun, Mon, Tue, Wed, Thu, Fri, Sat]

mutableList의 경우는, add와 remove를 통해 List에 item을 추가하거나, 제거할 수 있다.

만약 remove를 index를 이용해서 하고싶다면, weekDays.remove(item)가 아닌 weekDays.removeAt(index)를 사용하면 된다.

1.2 Set

Set의 가장 큰 특징은, 순서가 존재하지 않는다는 것이다.

순서가 존재하지 않는다는 뜻은, 아래 예제를 통해 알아보자.

Kotlin

fun mix(cl1: String, cl2: String) = if (setOf(cl1, cl2) == setOf("espresso","water")) "americano" else "wtf"

fun main() {
	println("espresso + water = "+mix("espresso","water"))
	println("water + espresso = "+mix("water","espresso"))
	print("water + milk \t = "+mix("water","milk"))
}

Result

espresso + water = americano
water + espresso = americano
water + milk     = wtf

위처럼, 물+에스프레소던, 에스프레소+물이던 잘 만들어지는 아메리카노 같은 경우에 set이 자주 사용된다. 물에 우유를 섞은 것은 별로 먹고싶지 않다;;

List와 마찬가지로, 빈 set을 가변형으로 선언하고 set에 add하는 식으로 사용할 수 있다.

Kotlin

fun main() {
	var someSet = setOf('1','2')
    print(someSet[0])
}

Result

ERROR : No get method providing array access

하지만, set은 순서를 가지지 않는 collection이므로, someSet[0]같은 index를 활용한 접근은 불가능하다.

Kotlin

fun main() {
	var someSet = mutableSetOf('1','2','3')
    someSet.add('1')
    print(someSet)
}

Result

[1, 2, 3]

또한 set은 중복되는 아이템을 가질 수 없으므로, 중복되는 원소를 input하면 원래 있던 아이템 위에 씌워진다고 생각하면 된다.

1.3 Map

map의 가장 큰 특징은 key-value 쌍으로 이루어진 데이터라는 점이다.

Kotlin

fun main() {
	var myCafe = mapOf(1 to "espresso", 10 to "water", 100 to "milk", 11 to "americano", 101 to "cafe latte", 110 to "wtf")
    print(myCafe)
    print(myCafe[1])
}

Result

{1=espresso, 10=water, 100=milk, 11=americano, 101=cafelatte, 110=wtf}
espresso

위와 같은 형식으로, "espresso"라는 값에 1이라는 키를 할당하는 형식으로 구성된다.

map의 index로 key를 입력하면, key에 해당하는 value가 return된다.

Kotlin

fun main() {
	var myCafe = mapOf(1 to "espresso", 1 to "water")
    print(myCafe)
}

Result

{1=water}

키는 반드시 유일한 값이어야 한다. 만약 동일한 키에 대한 값을 2번 할당하면, 더 나중에 할당된 값이 키에 할당된다.

Kotlin

var myCafe = mapOf(1 to "espresso", 10 to "water",
                   100 to "milk", 11 to "americano",
                   101 to "cafe latte", 110 to "wtf")

fun mix(key1: Int, key2: Int) {
    println("${myCafe[key1]} + ${myCafe[key2]} = ${myCafe[key1+key2]}")
}

fun main() {
	mix(1, 10)
	mix(100, 1)
	mix(100, 10)
}

Result

espresso + water = americano
milk + espresso = cafe latte
milk + water = wtf

위 코드는 2가지 재료의 키를 입력하면, 재료를 섞어 완성품을 만드는 코드다.

이런식으로, 키 값끼리는 서로 더해서 다른 키 값을 구할 수도 있다.

🤞 열거형Enum과 분기When

2.1 if문

if문을 사용하면 조건에 따라 원하는 값을 쉽게 받아낼 수 있다.

Kotlin에서 if문은 expression값을 반환하는 형태이기 때문에, 타 언어보다 조금 더 간결하게 사용할 수 있다.

Kotlin

fun main() {
    val weekdays = listOf("Sunday", "Monday", "Tuesday",
	    "Wednesday", "Thursday", "Friday", "Saturday")
    var answer = mutableListOf<String>()
    
    weekdays.map{
        var item = if (it == "Sunday" || it == "Saturday") "weekend" else "weekday"
        answer.add(item)
    }
    
    for (i in weekdays.indices) {
        println("${weekdays[i]} is ${answer[i]}")
    }
}

Result

Sunday is weekend
Monday is weekday
Tuesday is weekday
Wednesday is weekday
Thursday is weekday
Friday is weekday
Saturday is weekend

위 코드에서 가장 중요한 부분은 아래와 같다.

var item = if (it == "Sunday" || it == "Saturday") "weekend" else "weekday"
        answer.add(item)

if문이 itmap을 수행하는 weekdays의 각 원소에 따라서 weekend, weekday를 return하는 expression이기 때문에, item이라는 변수에 직접 할당할 수 있다.

이는 다른 언어보다 굉장히 직관적이고 간단한 형태로, Kotlin의 강점중 하나다.

2.2 열거형Enum

enum은 간단히 말해 데이터 보따리같은 느낌이다.

예시를 보며 어떤 느낌인지 이해해보자.

Kotlin

enum class WeekDays(val cnt: Int) {
	Sunday(0), Monday(1), Tuesday(2), Wednesday(3),
    Thursday(4), Friday(5), Saturday(6);	// enum 마지막은 ; 필수
    
    fun isWeek() = if (cnt == 0 || cnt == 6) "Weekend" else "Week"
}

fun main() {
    println(WeekDays.Monday.isWeek())
    print(WeekDays.Saturday.isWeek())
}

Result

Week
Weekend

Weekdays라는 보따리 안에, 일~토요일 까지의 데이터를 넣어주었다.

각 데이터는 0~6까지 멤버 변수를 가지고, 멤버 변수가 0이나 6이면 주말을 의미하도록 isWeek()함수를 정의하였다.

열거형의 데이터에 .을 통해 isWeek()함수를 사용하면 주말인지 평일인지 알 수 있는 식으로 작동한다.

2.3 분기When

When은 if문이 많이 필요한 상황에 사용되며, 다른 언어의 switch와 같은 역할을 한다.

입력되는 값들을 미리 분류하고, 해당 분류에 따른 값을 return한다.

When구문을 이용하면 enum에서 설명한 isWeek()를 다른 방법으로도 표현할 수 있다.

예시로 확인해보자.

Kotlin

fun isWeekend(week: String) =
    when (week) {
        "Sunday", "Saturday" -> "Weekend"
        "Friday" -> "Fire Friday"
        else -> "Weekdays"
    }

fun main() {
    println(isWeekend("Sunday"))
    println(isWeekend("Friday"))
    print(isWeekend("Tuesday"))
}

Result

Weekend
Fire Friday
Weekdays

이 경우는 if문이 적어서 비효율적으로 보일 수 있지만, if문이 복잡해지거나 길어질수록 when문이 진가를 발휘한다.

when은 확장성도 뛰어나고, 예외 처리도 가능하다는 장점이 있다.

2.4 When의 인자로 Enum 사용

언급했던 Enum 역시 When의 인자로 사용 가능하다.

앞의 두 예제를 묶어서 이해해보자.

Kotlin

enum class WeekDays(val cnt: Int) {
	Sunday(0), Monday(1), Tuesday(2), Wednesday(3),
    Thursday(4), Friday(5), Saturday(6);
}

fun isWeekend(week: WeekDays) =
    when (week) {
        WeekDays.Sunday, WeekDays.Saturday -> "Weekend"
        WeekDays.Friday -> "Fire Friday"
        else -> "Weekdays"
    }

fun main() {
    println(isWeekend(WeekDays.Sunday))
    println(isWeekend(WeekDays.Friday))
    print(isWeekend(WeekDays.Tuesday))
}

Result

Weekend
Fire Friday
Weekdays

When의 인자로 Enum을 받는 것도 가능하다.

🍀 마치며

기본적으로 존재하는 자료구조에 대해서는 대충 다뤘고, 대간단히 반복문에 대해서도 짚어보았다.

다음 시간에는 코틀린에서 사용되는 반복문에 대하여 다루어보려고 한다.

오늘 배운 내용과, 그 정도만 알고있어도 사실 프로그래머스나 백준같은 적당한 난이도의 알고리즘 문제를 작성하는데는 문제가 없는 수준이라고 생각한다.

참고한 블로그 : https://tourspace.tistory.com/64

태그:

카테고리:

업데이트:

댓글남기기