[Kotlin] ๋‘ ๊ฐ์ฒด์˜ ์„œ๋กœ ๋‹ค๋ฅธ ํ•„๋“œ์˜ ๊ฐ’ ์ฐพ๊ธฐ

๐Ÿ› ๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

  • kotlin : 1.8.22

๐Ÿ’ฌ ์ƒํ™ฉ ์„ค๋ช…

ํšŒ์‚ฌ์—์„œ ๊ฐœ๋ฐœ์„ ํ•˜๋˜ ์ค‘, ๋™์ผํ•œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋‘ ์ธ์Šคํ„ด์Šค์˜ ๊ฐ’์„ ๋น„๊ตํ•ด ๋‹ค๋ฅธ ๋ถ€๋ถ„์„ ์ฐพ์•„ ํ”„๋ก ํŠธ์—์„œ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ์ง์ด ํ•„์š”ํ–ˆ๋‹ค.

enum class PostCategory(val title: String) {  
    C1("์ž์œ  ๊ฒŒ์‹œํŒ"), C2("์ •๋ณด ๊ฒŒ์‹œํŒ")

    override fun toString(): String {  
        return title  
    }  
}

class Post() {  
    var title: String = ""  
    var content: String = ""  
    var isDeleted: Boolean = false
    var category: PostCategory = PostCategory.C1
    var writer: Member
}

์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์™€ ๊ฐ™์ด ์žˆ์„ ๋•Œ, ์ œ๋ชฉ์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด (์ œ๋ชฉ : ๊ธฐ์กด ๋‚ด์šฉ -> ๋ฐ”๋€ ๋‚ด์šฉ) ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ณด์—ฌ์ค˜์•ผํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์šฐ์„  ํšŒ์‚ฌ์—์„œ๋Š” ๊ธ‰ํ•˜๊ฒŒ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋‹ˆ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ–ˆ๋‹ค.

/**
* ๋ณ€ํ™”๋œ ๋ถ€๋ถ„์„ ์ฐพ์•„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
*/
fun findChanges(
    origin: Post, 
    target: Post
): List<Triple<String, String, String>> {  
    val list = mutableListOf<Triple<String, String, String>>()  

    if (origin.title != target.title) {  
        list += Triple("์ œ๋ชฉ", origin.title, target.title)  
    }  

    if (origin.content != target.content) {  
        list += Triple("๋‚ด์šฉ", origin.content, target.content)  
    }  

    if (origin.isDeleted != target.isDeleted) {  
        val t1 = if(origin.isDeleted) "์‚ญ์ œ๋จ" else "์‚ญ์ œ๋˜์ง€ ์•Š์Œ"  
        val t2 = if(target.isDeleted) "์‚ญ์ œ๋จ" else "์‚ญ์ œ๋˜์ง€ ์•Š์Œ"    
        list += Triple("์‚ญ์ œ ์—ฌ๋ถ€", t1, t2)  
    }

    if (origin.category != target.category) {  
        list += Triple("์นดํ…Œ๊ณ ๋ฆฌ", origin.category.title, target.category.title)  
    }

    return list  
}

์˜ˆ์ œ์—์„œ๋Š” ํ•„๋“œ๊ฐ€ 4๊ฐœ์ธ ๊ฐ„๋‹จํ•œ Post๋ฅผ ์˜ˆ์‹œ๋กœ ์ž‘์„ฑํ–ˆ์ง€๋งŒ, ์‹ค์ œ ์ฝ”๋“œ์—์„œ ๋น„๊ตํ•œ ํ•„๋“œ๋Š” 8๊ฐ€์ง€ ์ •๋„ ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ž‘์„ฑ์„ ํ•˜๋‹ค๋ณด๋‹ˆ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ง์ ‘ ๋น„๊ตํ•ด์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์žˆ์—ˆ๊ณ , ๋น„๊ตํ•˜๋Š” ๊ณผ์ •์—์„œ ์‹ค์ˆ˜๋„ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์–ด ์œ„ํ—˜ํ•œ ์ฝ”๋“œ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

โœ… ํ•ด๊ฒฐ ๊ณผ์ •

์‚ฌ์‹ค ํ˜„์žฌ ํด๋ž˜์Šค์—์„œ๋งŒ ์ด๋Ÿฐ ๊ธฐ๋Šฅ์ด ์กด์žฌํ•œ๋‹ค๋ฉด ์œ„ ๋ฐฉ์‹์œผ๋กœ ๊ตฌ์„ฑํ•ด๋„ ํฌ๊ฒŒ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค. ํ•˜์ง€๋งŒ ๋‚˜๋ฆ„ ๊ฐœ๋ฐœ์ž๋กœ์„œ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๊ณ  ์‹ถ์€ ์š•์‹ฌ์ด ์ƒ๊ฒผ๊ณ , ๋” ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์„๊นŒ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์„ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

1. ์š”๊ตฌ ๋ถ„์„

ํ˜„์žฌ ๋‚ด๊ฐ€ ๋งŒ๋“œ๋ ค๊ณ  ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ๋ฌด์—‡์„ ํ•„์š”๋กœ ํ•˜๋Š”์ง€ ๋ถ„์„ํ–ˆ๋‹ค.

  • ๋ณ€๊ฒฝ๋œ ํ”„๋กœํผํ‹ฐ์˜ ๋ ˆ์ด๋ธ”
    • ์˜ˆ) title -> ์ œ๋ชฉ
  • ๋ณ€๊ฒฝ๋œ ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’
    • ์˜ˆ) Boolean -> ์‚ฌ์šฉ ํ•จ / ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ || ์‚ญ์ œ๋จ / ์‚ญ์ œ๋˜์ง€ ์•Š์Œ

์ด๊ฒƒ๋งŒ ๋ด๋„ ๋ฒŒ์จ ๋ณต์žกํ•˜๋‹ค. Boolean ํƒ€์ž…์ด๋”๋ผ๋„ ๋™์ผํ•œ ๋ ˆ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ, ๊ธฐํš ์˜๋„์— ์˜ํ•ด ๋ณ€๊ฒฝ๋œ ๊ฐ’๋“ค์ด ๋ณด์—ฌ์งˆ ์ˆœ์„œ๋„ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

2. ํ‹€ ๋งŒ๋“ค๊ธฐ

์šฐ์„ , ํด๋ผ์ด์–ธํŠธ์—์„œ ์•„๋ž˜ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณด๋‚ด์ค€๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

data class Item(  
    val order: Int,  
    val propertyName: String,  
    val label: String,  
    val v1: String = "",  
    val v2: String = ""  
)
val items = listOf(  
    Item(1, "title", "์ œ๋ชฉ"),  
    Item(2, "writer", "์ž‘์„ฑ์ž", origin.writer.username, changed.writer.username), 
    Item(3, "category", "์นดํ…Œ๊ณ ๋ฆฌ"),  
    Item(4, "isDeleted", "์‚ญ์ œ์—ฌ๋ถ€", "์‚ญ์ œ๋จ", "์‚ญ์ œ๋˜์ง€ ์•Š์Œ")
)

findChanges(items)

ํ•ด๋‹น ์ •๋ณด๋ฅผ ํ† ๋Œ€๋กœ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ œ๋„ค๋ฆญ์œผ๋กœ ๋“ค์–ด์˜จ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋ฐ›๊ณ , ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฐ๊ฐ์˜ ํ•„๋“œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ด์ค€ ํ•„๋“œ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๋น„๊ตํ•  ๊ฒƒ์ด๋‹ค.

์ด์ œ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์œผ๋‹ˆ, ์ •ํ™•ํ•œ ๋น„๊ต๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก equals, hashCode๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒŒ ๊ฐ•์ œํ•ด๋ณด์ž.

interface Detectable {  
    override fun hashCode(): Int  
    override fun equals(other: Any?): Boolean  
}
class Post(  
    val title: String = "",  
    val content: String = "",  
    val isDeleted: Boolean = false,  
    val category: PostCategory = PostCategory.C1,  
    val writer: Member  
) : Detectable {

    override fun equals(other: Any?): Boolean {  
        ...
    }  

    override fun hashCode(): Int {  
        ...
    }  

}

์œ„์™€ ๊ฐ™์ด Detectable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๋ฉด, ๋‚ด๋ถ€์— ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋”๋ผ๋„ ์ •ํ™•ํ•œ ๋น„๊ต๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

3. ๊ตฌํ˜„

์•ž์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ œ๋„ค๋ฆญ์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋ฐ›์•„์˜ฌ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋Ÿฐํƒ€์ž„์—๋„ ํƒ€์ž… ์ •๋ณด๊ฐ€ ์‚ด์•„์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— inline ํ•จ์ˆ˜์™€ reified๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

/**  
* ๋‘ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•ด ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์„ ์ฐพ๋Š” ํ•จ์ˆ˜  
* @param origin ๊ธฐ์กด ๊ฐ์ฒด  
* @param target ๋น„๊ต ๋Œ€์ƒ ๊ฐ์ฒด  
* @param itemList ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ  
* */  
inline fun <reified T : Detectable> findChanges(  
    origin: T,  
    target: T,  
    itemList: List<Item>  
): List<Item> { ... }

inline ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ํ•จ์ˆ˜ ํ˜ธ์ถœ๋ถ€๊ฐ€ ํ•จ์ˆ˜ ๋ณธ๋ฌธ์œผ๋กœ ๋Œ€์น˜๋œ๋‹ค. ๋•๋ถ„์— reified๋ฅผ ์‚ฌ์šฉํ•ด ๋Ÿฐํƒ€์ž„์—๋„ ์ œ๋„ค๋ฆญ ํƒ€์ž… ์ •๋ณด๋ฅผ ๊ฐ–๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๋งŒ์•ฝ ์ผ๋ฐ˜ ํ•จ์ˆ˜์™€ reified ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

Cannot use 'T' as reified type parameter. Use a class instead.

์ œ๋„ค๋ฆญ์€ ๋Ÿฐํƒ€์ž„์— ํƒ€์ž… ์ •๋ณด๊ฐ€ ์†Œ๊ฑฐ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž… ์ •๋ณด๋ฅผ ์‹ค์ฒดํ™” ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด reified ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น ํ‚ค์›Œ๋“œ๋Š” inline ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜ํ•œ, T๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Any?๋ฅผ ์ƒํ•œ์œผ๋กœ ์ง€์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Detectable์„ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด๋งŒ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

Kotlin in action 8์žฅ(๊ณ ์ฐจ ํ•จ์ˆ˜; ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ๋žŒ๋‹ค ์‚ฌ์šฉ)์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๋ณด๋ฉด, inline ํ•จ์ˆ˜๋Š” ๋žŒ๋‹ค์™€ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๊ธฐ์—” ์• ๋งคํ•˜๋‹ˆ ์šฐ์„  ์ง„ํ–‰ํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

์ด์ œ ...์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž.

// ์‹ค์ฒดํ™”๋œ T ํƒ€์ž…์˜ ํด๋ž˜์Šค ์ •๋ณด ๋ฐ›์•„์˜ค๊ธฐ
val clazz = T::class // Type: KClass<T>

// ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹ด์„ Item ๋ฆฌ์ŠคํŠธ
val result = mutableListOf<Item>()

for (property in clazz.memberProperties) {  
    val propertyName = property.name
    itemList.find { it.propertyName == propertyName }?.let {  
        ...
    }  
}

์œ„์™€ ๊ฐ™์ด clazz๊ฐ€ ๊ฐ–๊ณ ์žˆ๋Š” ๋ฉค๋ฒ„ ํ”„๋กœํผํ‹ฐ๋“ค์„ ๊ฐ€์ ธ์™€ iterator๋ฅผ ๋Œ๋ ค์ฃผ๊ณ , ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฆ„์ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ด์ค€ itemList์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•ด์ค€๋‹ค. ๋งŒ์•ฝ ํฌํ•จ์ด ๋˜์–ด์žˆ์„ ๊ฒฝ์šฐ ๊ฐ’์— ๋Œ€ํ•œ ๋น„๊ต๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋๋‚œ๋‹ค.

// ๊ธฐ์กด ๊ฐ์ฒด์˜ ๊ฐ’
val originValue = property.get(origin).toString()  
// ํƒ€๊ฒŸ ๊ฐ์ฒด์˜ ๊ฐ’
val targetValue = property.get(target).toString()  

// ๋‘ ๊ฐ’์ด ๋‹ค๋ฅธ์ง€ ๋น„๊ต
if (originValue != targetValue) {  
    // item ๊ฐ์ฒด์˜ v1์ด ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ originValue๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
    val v1 = it.v1.ifEmpty { originValue }  
    // item ๊ฐ์ฒด์˜ v2๊ฐ€ ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ targetValue๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
    val v2 = it.v2.ifEmpty { targetValue }  

    // ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
    result += Item(it.order, it.propertyName, it.label, v1, v2)  
}

๊ธฐ์กด์—๋Š” ๋‚ด๊ฐ€ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ๋น„๊ตํ•ด์•ผ ํ–ˆ์ง€๋งŒ, ์ด์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฆฌ์ŠคํŠธ๋งŒ ๋งŒ๋“ค์–ด์„œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋‘ ๊ฐ์ฒด์˜ ๊ฐ’์„ ์‰ฝ๊ฒŒ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค.

val items = listOf(  
   Item(1, "title", "์ œ๋ชฉ"),  
   Item(2, "writer", "์ž‘์„ฑ์ž", origin.writer.username, changed.writer.username),
   Item(3, "category", "์นดํ…Œ๊ณ ๋ฆฌ"),  
   Item(4, "isDeleted", "์‚ญ์ œ์—ฌ๋ถ€", "์‚ญ์ œ๋จ", "์‚ญ์ œ๋˜์ง€ ์•Š์Œ")  
)

์ „์ฒด ์ฝ”๋“œ์™€ ๊ฒฐ๊ณผ ๊ฐ’์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

/**  
 * ๋‘ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•ด ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์„ ์ฐพ๋Š” ํ•จ์ˆ˜  
 * @param origin ๊ธฐ์กด ๊ฐ์ฒด  
 * @param target ๋น„๊ต ๋Œ€์ƒ ๊ฐ์ฒด  
 * @param itemList ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ  
* */  
inline fun <reified T : Detectable> findChanges(  
    origin: T,  
    target: T,  
    itemList: List<Item>  
): List<Item> {  
    val clazz = T::class  

    val result = mutableListOf<Item>()  

    for (property in clazz.memberProperties) {  
        val propertyName = property.name  

        itemList.find { it.propertyName == propertyName }?.let {  
            val originValue = property.get(origin).toString()  
            val targetValue = property.get(target).toString()  

            if (originValue != targetValue) {  
            val v1 = it.v1.ifEmpty { originValue }  
            val v2 = it.v2.ifEmpty { targetValue }  

            result += Item(it.order, it.propertyName, it.label, v1, v2)  
            }  
        }  
    }  
    return result.sortedBy { it.order }  
}
// ๊ฒฐ๊ณผ (title์€ ๊ฐ’์ด ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€๋˜์ง€ ์•Š์Œ)
[Item(order=2, field=category, label=์นดํ…Œ๊ณ ๋ฆฌ, v1=์ž์œ  ๊ฒŒ์‹œํŒ, v2=์ •๋ณด ๊ฒŒ์‹œํŒ),
Item(order=3, field=isDeleted, label=์‚ญ์ œ์—ฌ๋ถ€, v1=์‚ญ์ œ๋จ, v2=์‚ญ์ œ๋˜์ง€ ์•Š์Œ),
Item(order=4, field=writer, label=์ž‘์„ฑ์ž, v1=admin, v2=tester)]

๐Ÿค” ํšŒ๊ณ 

์ฝ”ํ‹€๋ฆฐ์„ ์‹œ์ž‘ํ•œ์ง€ 2๋‹ฌ ์ •๋„์ธ์ง€๋ผ ๋งŽ์ด ๋ฏธ์ˆ™ํ•˜๋‹ค. ์‚ฌ์‹ค ์ฒ˜์Œ์— ๋น„๊ตํ•œ ๋ฐฉ์‹์€ O(N) ๋งŒํผ์˜ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€์ง€๋งŒ, ๋ณ€๊ฒฝํ•œ ์ฝ”๋“œ๋Š” O(N^2) ๋งŒํผ์˜ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค. ๋•Œ๋ฌธ์— ์ฒ˜์Œ์— ๋น„๊ตํ•œ ๋ฐฉ์‹์ด ์„ฑ๋Šฅ์ ์œผ๋กœ ๋” ์ข‹์ง€๋งŒ, ํ•˜๋‚˜ํ•˜๋‚˜ ๋น„๊ต๋ฅผ ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ถˆํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์ •๋„์˜ ์„ฑ๋Šฅ ์ฐจ์ด๋Š” ๊ฐ์ˆ˜ํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค. ์ด๋ณด๋‹ค ๋” ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„์ง€ ๋” ๊ณ ๋ฏผํ•ด๋ณด๊ณ , ๋ฆฌํŒฉํ„ฐ๋งํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ์•ผ๊ฒ ๋‹ค!

๋ ˆํผ๋Ÿฐ์Šค

  • Kotlin In Action - Chapter08; ๊ณ ์ฐจ ํ•จ์ˆ˜; ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ๋žŒ๋‹ค ์‚ฌ์šฉ
  • Kotlin In Action - Chapter09; ์ œ๋„ค๋ฆญ์Šค