[HeadFirst] Kotlin collections :: Set

Set for unique value

list 는 원소간에 동일한 값이 들어오는것을 허락한다. 하지만 set 자료 구조는 동일한 값이 들어오는걸 허락하지 않는다.

fun main() {
    val nameSet = setOf("Smith","Nick","Nick")
    println(nameSet.size)
}

출력 결과는 어떻게 될까? size 는 2이다. set 을 초기화하는 과정에서 중복값이 들어올 수 있지만, 컴파일러는 이를 컴파일 과정에서 에러로 잡아내기보다는 컴파일 과정에서 중복되는 값 중에 하나만 가져가게끔 한다.

set 은 정렬된 자료구조가 아니기 때문에 get 을 이용할 수 없다. 대신 contains() 를 이용할 수 있으므로 이를 get 대신 사용할 수 있다. 그리고 역시 for 을 이용해서 내부 값들에 접근할 수 있다.

fun main() {
    val nameSet = setOf("Smith","Nick","Nick")
    val isSmithIn: Boolean = nameSet.contains("Smith")
    
    for (item in nameSet) println(item)
}

set 은 어떻게 중복값을 인지할까?

step1 : hash code

set 객체 정보를 저장할 때 hash code 를 이용한다. set 은 hash code 를 원소를 저장하는 바구니에 붙은 라벨로 활용한다고 생각하면 된다. 따라서 새로운 객체를 저장하려고 하면 기존 hashCode 들과 비교하고 같은 hash code 가 있으면 저장을 막는다.

step2 : === operator

set 은 hash code 검사만 하는게 아니다. === 연산까지 시행한다. == 이 equals() 함수를 이용했던 것과는 달리 === 연산은 두 변수의 참조값이 같은지 검사한다. 기존에 저장된 모든 값들과 참조값이 달라야 step2 통과이다.

step3 : == operator

마지막으로 == 연산까지 시행하고 나서 이를 모두 통과하면 새로운 객체를 저장한다.

hash code & equality

위에 나와있는 대로 hash code 검증 뒤에, === 검증, == 검증을 한다. 그런데 만약 Recipe 객체의 title 이 똑같으면 같은 객체로 인식하게 하고 싶으면? hashCode() 함수부터 override 해야한다. (사실 가장 편한 방법은 Recipe 객체를 data class 로 선언하는 것이다.)

class Recipe (val title: String) {}

fun main() {
    val a = Recipe("rice")
    val b = Recipe("rice")
    println("a: ${a.hashCode()} b : ${b.hashCode()}") // different
    println(a === b) // false
    println(a == b) // false
}

override hashCode(), equals() 규칙

만약 data class 를 사용하는 것이 아니라 손수 override 하기로 마음 먹었다면 몇가지 지켜야 하는 규칙이 있다.

  • hashCode() 의 기본 동작은 각 객체마다 유니크한 integer 값을 만드는 것이다.(하지만 낮은 확률로 동일한 integer 를 가질 수 있다)
  • equals() 의 기본 동작은 === 검사를 포함하고 있다. 따라서 변수가 동일한 객체를 참조하고 있는지 보는 것이다.
  • 두 obejct 를 equal 로 인식하게 하고 싶다면, 두 object 의 hash code 는 반드시 일치해야한다.
  • 두 obejct 를 equal 로 인식하게 하고 싶다면, 어느 object 에서 equals() 를 호출해서 검증하든 true 를 반환해야한다.
  • 두 object 의 hash code 가 일치한다고 하더라도 둘이 반드시 equal 로 인식되어야 할 필요는 없다. 하지만 반대의 경우는 아니다.
  • 따라서 equals() 를 override 할 경우 hashCode() 도 override 해야한다.

a.equals(b) == true 라면 a.hashCode() == b.hashCode() 여야만 한다.

MutableSet

fun main() {
    val mySet = mutableSetOf("Hello", "World", "Bye")
    mySet.add("Earth")
    mySet.remove("Hello")
    mySet.clear()
    val copySet = mySet.toSet()
    val copySet2 = mySet.toMutableSet()
    val copyList = mySet.toList() // 반대로 list.toSet() 도 가능

좋은 웹페이지 즐겨찾기