[Kotlin] - Pair

Pair란

Pair란, 한 쌍;두 부분이 함께 붙어 하나를 이루는 것을 의미한다.

kotlin에서도 동일하게 쌍을 의미하는 클래스이며, 클래스 구조는 아래와 같이 생겼다.

public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable

자세한 내용은 공식 문서를 참고하면 좋을 것 같다.

Pair의 사용

앞서 설명한 것과 같이 2개의 변수를 묶어서 사용할 수 있으며, 어떠한 타입이든 넣을 수 있다.

데이터 저장

아래 코드와 같이 다양한 방법으로 정의가 가능하다.

var a = Pair(1, "짱구")
val b = Pair<Int, String>(second = "철수", first = 2)
val (c1, c2) = Pair(3, "유리")
val (d1, d2) = 4 to "훈발롬"

약간 생소한 코드가 있다면 c1, c2 변수를 괄호로 묶어 사용하는 것이다.
Pair가 한 쌍을 의미하는 것처럼 한 쌍의 변수로 묶어서 사용하는 것이다.

데이터 출력

출력은 Pair의 첫 부분을 사용하고 싶다면 first를 호출하고, 두 번째 부분을 사용하고 싶다면 second를 호출하면 된다.

println("a.first = ${a.first} \t a.second = ${a.second}")

println("a = $a")

println("c.first = $c1 \t c.second = $c2")

// a.first = 1      a.second = 짱구
println("a.first = ${a.first} \t a.second = ${a.second}")
// a = (1, 짱구)
println("a = $a")

// b.first = 2      b.second = 철수
println("b.first = ${b.first} \t b.second = ${b.second}")
// b = (2, 철수)
println("b = $b")

// c.first = 3        c.second = 유리
println("c.first = $c1 \t c.second = $c2")

// d.first = 4 	     d.second = 훈발롬
println("d.first = $d1 \t d.second = $d2")

데이터 수정

앞서 클래스 구조를 보면 알듯이 val로 되어 있어서 데이터를 수정할 수 없다.
그럼에도 꼭 수정이 필요한 경우 copy를 통해 다시 할당하는 방식으로 할 수 있다.

a = a.copy(first = 5, second = "돌")

데이터 정렬

Pair는 다른 클래스와 다르게 PriorityQueue를 통해 정렬할 수 없다.

fun main() {
    val pq = PriorityQueue<Pair<Int, Int>>()
    pq.offer(1 to 1)
    pq.offer(2 to 2)

    while (!pq.isEmpty()) {
        val cur = pq.poll()

        println(cur.first)
    }
}

위와 같이 작성하면 컴파일 타임에는 에러나 나지 않지만, 런타임에서 아래와 같은 에러가 발생한다.

Exception in thread "main" java.lang.ClassCastException: 
class kotlin.Pair cannot be cast to class java.lang.Comparable 
(kotlin.Pair is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')

에러 내용을 살펴보면 Pair 클래스는 Comparable로 캐스트할 수 없다는 내용이다.
즉, Comparable을 구현하지 않아 무엇과 비교를 해서 정렬할지 정의되어 있지 않다는 것이다.

이를 해결하는 방법은 생각보다 간단하다.

// 방식 1
val pq = PriorityQueue<Pair<Int, Int>>(Comparator() { a, b -> a.first - b.first })

// 방식 2
val pq = PriorityQueue<Pair<Int, Int>> { a, b -> a.first - b.first }

위와 같이 Comparator를 제공해 정렬을 해주면 된다.