[Kotlin] 문법 - 반복문 & 배열 & 해시 & 정렬

2025. 2. 13. 13:17·개발/모바일
반응형

오늘은 Kotlin 문법에 대해서 다뤄보려고 합니다.

저번에 코딩테스트를 한 번 해봤는데, Kotlin 문법을 까먹었더니 확장함수를 쓸 수가 없어서 너무 불편하더라고요, 그래서 이번 포스트를 작성하게 됐습니다.


먼저, 반복문에 대해서 알아보겠습니다.

 

반복문

 

1. 기본 for와 범위 연산자(..)

// N값이 5인 경우: 1, 2, 3, 4, 5
for (stage in 1..N) { }

 

- 끝 값을 포함합니다. (N값이 5인 경우: 1, 2, 3, 4, 5)

 

2. until

// N값이 5인 경우: 1, 2, 3, 4
for (stage in 1 until N) { }

 

- 끝 값을 포함하지 않습니다. (N값이 5인 경우:  1, 2, 3, 4)

- 배열의 사이즈만큼 반복할 때 유용해 보입니다.

 

3. forEach

(1..N).forEach { stage -> }

 

- continue와 break 사용이 불가능합니다.

- 코드가 간결해집니다.

- 함수형 프로그래밍에 적합합니다.

 

4. repeat

repeat(N) { index -> }

 

- continue와 break 사용이 불가능합니다.

- 0부터 시작하는 인덱스를 제공합니다. 

- 배열의 크기 만큼만 반복합니다.

 

5. while

var stage = 1
while (stage <= N) {
    stage++
}

 

- 조건에 따른 유연한 반복이 가능합니다.

- 무한 루프의 위험이 있습니다.

 

6. indices

for (i in stages.indices) {
    val stage = stages[i]
}

 

- 0부터 시작하는 인덱스를 제공합니다. 

- 배열의 크기 만큼만 반복합니다.

- repeat과 동일한 기능입니다.

 

7. withIndex

for ((index, stage) in stages.withIndex()) { }

 

- 인덱스와 값을 동시에 받을 수 있습니다.

 

8. forEachIndexed

stages.forEachIndexed { index, stage -> }

 

- 인덱스와 값을 동시에 받을 수 있습니다.

- forEach와 마찬가지로 함수형 프로그래밍에 적합합니다.

 

9. map과 range

(1..N).map { stage -> }
val stageArray: Array<Int> = arrayOf(6, 7, 4, 2)
val stageCopy = (1..stageArray.size).map { index ->
    stageArray[index - 1] * 2
}
for((index, stage) in stageArray.withIndex()) {
    println("[원본] index: $index, stage: $stage")
}
println("[복제] stageCopy: $stageCopy")

// [원본] index: 0, stage: 6
// [원본] index: 1, stage: 7
// [원본] index: 2, stage: 4
// [원본] index: 3, stage: 2
// [복제] stageCopy: [12, 14, 8, 4]

 

- 새로운 컬렉션을 생성합니다.

- 원본 데이터는 변경되지 않습니다.

 

10. do-while

var stage = 1
do {
    println("Stage: $stage")
    stage++
} while (stage <= N)

 

- while 조건과 관계 없이 최소 1번은 실행합니다.

- 반복 조건을 마지막에 체크합니다.

 

11. downTo

// 기본 사용법
for (i in N downTo 1) {
    println(i)  // N부터 1까지 역순으로 출력
}

// step 사용
for (i in N downTo 1 step 2) {
    println(i)  // 2칸씩 건너뛰며 역순으로
}

 

- 역순 반복을 원할 때 유용합니다.

- step으로 감소 간격 지정이 가능합니다.

- 끝 값을 포함합니다.

 

12. sequence

sequence {
    for (stage in 1..N) {
        yield(stage)
    }
}

 

- 지연 평가로 메모리 효율적

- 체이닝 연산에 효과적

 

'sequence'는 추가적인 설명을 더 드리겠습니다.

* 일반적인 처리 방식 (map, filter 사용)

val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers
    .map { it * 2 }  // [2, 4, 6, 8, 10] 새로운 리스트 생성
    .filter { it > 5 }  // [6, 8, 10] 또 새로운 리스트 생성
println(result)  // [6, 8, 10]

 

* sequence 처리 방식

val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers.asSequence()
    .map { it * 2 }  // 아직 계산하지 않음
    .filter { it > 5 }  // 아직 계산하지 않음
    .toList()  // 이때 실제로 계산
println(result)  // [6, 8, 10]

 

* 예시

// 일반 처리: 과정 출력해보기
val numbers = listOf(1, 2, 3)
println("일반 처리 시작")
val result1 = numbers
    .map { 
        println("map: $it")
        it * 2 
    }
    .filter { 
        println("filter: $it")
        it > 3 
    }
println("결과: $result1")

// sequence 처리: 과정 출력해보기
println("\nsequence 처리 시작")
val result2 = numbers.asSequence()
    .map { 
        println("map: $it")
        it * 2 
    }
    .filter { 
        println("filter: $it")
        it > 3 
    }
    .toList()
println("결과: $result2")
일반 처리 시작
map: 1
map: 2
map: 3
filter: 2
filter: 4
filter: 6
결과: [4, 6]

sequence 처리 시작
map: 1
filter: 2
map: 2
filter: 4
map: 3
filter: 6
결과: [4, 6]

 

자주 사용할 것 같은 반복문: 범위 연산자(..), until, indices, withIndex 


이번엔 배열에 대해서 다뤄보겠습니다.

 

배열

 

1. Array와 arrayOf()

// Array: 크기가 고정된 배열
val arr1 = Array(5) { 0 }  // [0, 0, 0, 0, 0]
val arr2 = Array(3) { it }  // [0, 1, 2]
val arr3 = Array(5) { it * 2 }  // [0, 2, 4, 6, 8]

// arrayOf(): 요소를 직접 지정해서 배열 생성
val arr4 = arrayOf(1, 2, 3)  // [1, 2, 3]

 

- 크기가 고정됩니다.

- 인덱스로 접근합니다.

 

2. ArrayList와 arrayListOf()

// ArrayList: 동적 크기 리스트
val list1 = ArrayList<Int>()  // 빈 리스트
list1.add(1)  // 요소 추가 가능

// arrayListOf(): 초기 요소와 함께 ArrayList 생성
val list2 = arrayListOf(1, 2, 3)  // [1, 2, 3]

 

- 크기가 동적으로 변합니다.

- 요소의 추가/삭제가 가능합니다.

 

3. mutableListOf()

val list = mutableListOf(1, 2, 3)
list.add(4)      // 추가 가능
list[0] = 10     // 수정 가능
list.remove(2)   // 삭제 가능

 

- 수정 가능한 리스트입니다.

- ArrayList와 비슷하지만 더 추상화된 인터페이스입니다.

 

좀 더 추가적인 설명을 드리겠습니다.

// ArrayList는 구체적인 구현체를 직접 사용
val arrayList = ArrayList<Int>()
arrayList.add(1)
arrayList.ensureCapacity(100)  // ArrayList의 고유 메서드 사용 가능

// mutableListOf는 MutableList 인터페이스를 통해 사용
val mutableList = mutableListOf<Int>()
mutableList.add(1)
// mutableList.ensureCapacity(100)  // 컴파일 에러, MutableList 인터페이스에 없는 메서드

 

- ArrayList는 실제 구현체를 직접 사용하므로 ArrayList의 모든 구체적인 메서드를 사용할 수 있습니다.

- mutableListOf는 MutableList 인터페이스를 통해 접근하므로 인터페이스에 정의된 메서드만 사용이 가능합니다.

 

4. IntArray (기본타입 배열)

// 크기와 초기값으로 생성
val arr1 = IntArray(5)        // [0, 0, 0, 0, 0]
val arr2 = IntArray(5) { it } // [0, 1, 2, 3, 4]

// 직접 값 지정
val arr3 = intArrayOf(1, 2, 3)  // [1, 2, 3]

 

- 기본 타입(int) 배열 (참고로 Double 등등 가능합니다. *DoubleArray)

- Array<Int>보다 성능이 좋음

 

성능 차이가 나는 이유에 대해서 좀 더 설명을 드리겠습니다.

* 메모리 사용

- IntArray: 순수하게 int 값만 저장 (4바이트 × 배열 크기)

- Array<Int>: 각 요소가 Integer 객체를 참조 (참조 8바이트 + 객체 오버헤드 12바이트 + int 값 4바이트) × 배열 크기

 

*접근 속도

- IntArray: 메모리에 직접 접근

- Array<Int>: 참조를 통해 접근

 

따라서 기본 타입(Int, Long, Double 등)을 다룰 때는 가능한 IntArray, LongArray, DoubleArray 등을 사용하는 것이 성능상 유리합니다!

 

* Array & arrayOf: 고정 배열에 적합

* ArrayList & arrayListOf: 추가, 삭제가 필요한 배열에 적합

* mutableListOf: 추가, 삭제, 수정이 필요한 배열에 적합

* IntArray: 기본 배열에 적합


이번엔 해시에 대해서 알아보겠습니다.

 

해시

 

1. HashMap

// HashMap 생성
val scores = hashMapOf<String, Int>()  // 빈 HashMap
val fruits = hashMapOf(
    "사과" to 1000,
    "바나나" to 2000,
    "딸기" to 3000
)

// 요소 추가/수정
scores["Kim"] = 95
scores["Lee"] = 88

// 값 가져오기
println(fruits["사과"])  // 1000
println(fruits.get("바나나"))  // 2000
println(fruits.getOrDefault("망고", 0))  // 0

// 키/값 존재 여부 확인
println(fruits.containsKey("사과"))  // true
println(fruits.containsValue(1000))  // true

// 요소 제거
fruits.remove("바나나")

// 순회하기
for ((key, value) in fruits) {
    println("$key: $value")
}

 

- 키&값 쌍으로 데이터를 저장합니다.


* 각 요소에 대한 추가 정보를 저장해야하는 경우

* 키를 통한 빠른 검색이 필요한 경우

 

2. HashSet

// HashSet 생성
val numberSet = hashSetOf<Int>()  // 빈 HashSet
val fruitsSet = hashSetOf("사과", "바나나", "딸기")  // 초기값이 있는 HashSet

// 요소 추가
numberSet.add(1)
numberSet.add(2)

// 요소 존재 여부 확인
println(fruitsSet.contains("사과"))  // true

// 요소 제거
fruitsSet.remove("바나나")

// 크기 확인
println(fruitsSet.size)  // 2

 

- 중복 제거가 필요한 경우 매우 효율적입니다.

- 단일 값만 저장합니다.


* 단순히 고유한 값들의 집합이 필요한 경우

* 집합 연산(교집합, 합집합 등)이 필요한 경우


이번엔 정렬에 대해서 알아보겠습니다.

 

정렬

 

1. sorted / sortedBy & sort / sortBy

// sorted(): 오름차순 정렬 (새로운 리스트 반환)
val numbers = listOf(3, 1, 4, 1, 5, 9)
val sortedNumbers = numbers.sorted() // [1, 1, 3, 4, 5, 9]

// sortedDescending(): 내림차순 정렬
val descendingNumbers = numbers.sortedDescending() // [9, 5, 4, 3, 1, 1]

// sort(): 변경 가능한 리스트 직접 정렬
val mutableNumbers = mutableListOf(3, 1, 4, 1, 5, 9)
mutableNumbers.sort() // 리스트 자체가 정렬됨

// sortDescending(): 변경 가능한 리스트 내림차순 정렬
mutableNumbers.sortDescending()
data class Person(val name: String, val age: Int)

val people = listOf(
    Person("Kim", 25),
    Person("Lee", 20),
    Person("Park", 30)
)

// sortedBy: 특정 프로퍼티로 정렬
val sortedByAge = people.sortedBy { it.age }
val sortedByName = people.sortedBy { it.name }

// sortedByDescending: 특정 프로퍼티로 내림차순 정렬
val sortedByAgeDesc = people.sortedByDescending { it.age }

// sortedWith: 여러 조건으로 정렬
val sortedWithComparator = people.sortedWith(
    compareBy<Person> { it.age }.thenBy { it.name }
)
// compareBy로 복잡한 정렬 조건 만들기
val complexSort = people.sortedWith(
    compareBy(
        { it.name.length }, // 먼저 이름 길이로 정렬
        { it.age },         // 그 다음 나이로 정렬
        { it.name }         // 마지막으로 이름으로 정렬
    )
)

// 널 값 처리
data class User(val name: String, val score: Int?)
val users = listOf(
    User("Kim", 80),
    User("Lee", null),
    User("Park", 90)
)

// nullsLast: null 값을 마지막으로
val sortedWithNulls = users.sortedWith(
    compareBy(nullsLast()) { it.score }
)

 

- sorted / sortedBy: 새로운 리스트를 생성하므로 메모리를 더 사용하지만, 원본 리스트를 보존합니다.

- sort / sortBy: 원본 리스트를 직접 수정하므로 메모리 효율적이지만, 원본이 변경됩니다.

 

2. compareBy

// 1. 단일 조건 compareBy
val people = listOf(
    Person("Kim", 25),
    Person("Lee", 20),
    Person("Park", 30)
)

// 나이로 정렬
val sortedByAge = people.sortedWith(compareBy { it.age })
// 결과: [Person("Lee", 20), Person("Kim", 25), Person("Park", 30)]

// 이름으로 정렬
val sortedByName = people.sortedWith(compareBy { it.name })
// 결과: [Person("Kim", 25), Person("Lee", 20), Person("Park", 30)]

 

- compareBy: 정렬 기준을 만드는 함수입니다.

 

3. thenBy

data class Student(
    val grade: Int,    // 학년
    val name: String,  // 이름
    val score: Int     // 점수
)

val students = listOf(
    Student(2, "Kim", 85),
    Student(1, "Lee", 90),
    Student(2, "Park", 85),
    Student(1, "Choi", 95)
)

// 1. 학년 순으로 정렬하고, 
// 2. 학년이 같다면 점수로 정렬하고,
// 3. 점수도 같다면 이름순으로 정렬
val sorted = students.sortedWith(
    compareBy<Student> { it.grade }    // 첫 번째 조건
        .thenByDescending { it.score } // 두 번째 조건 (내림차순)
        .thenBy { it.name }           // 세 번째 조건
)

// 결과 출력
sorted.forEach { student ->
    println("${student.grade}학년 ${student.name}: ${student.score}점")
}

 

- thenBy: 첫 번째 조건이 같을 때, 그 다음 조건으로 정렬하고 싶을 때 사용합니다.

 

4. sortWith

// 1. 기본적인 sortWith 사용
val numbers = mutableListOf(3, 1, 4, 1, 5, 9)
numbers.sortWith(compareBy { it })  // [1, 1, 3, 4, 5, 9]

// 2. 객체 정렬
data class Person(val name: String, val age: Int)

val people = mutableListOf(
    Person("Kim", 25),
    Person("Lee", 20),
    Person("Park", 30)
)

// 나이순으로 정렬
people.sortWith(compareBy { it.age })

// 여러 조건으로 정렬 (나이 오름차순, 이름 내림차순)
people.sortWith(
    compareBy<Person> { it.age }
        .thenByDescending { it.name }
)

// null을 처음에 위치시키기
val nullsFirst = people.sortedWith(
    compareBy(
        nullsFirst() { it.age },  // null이 앞으로
        { it.name }
    )
)

// null을 마지막에 위치시키기
val nullsLast = people.sortedWith(
    compareBy(
        nullsLast() { it.age },   // null이 뒤로
        { it.name }
    )
)

 

- sortWith: 커스텀 비교자(Comparator)를 사용하여 MutableList를 정렬하는 함수입니다. 원본 리스트를 직접 정렬합니다.


마지막으로 확장 함수에 대해서 다루고 마치겠습니다.

 

확장 함수

 

1. 배열 관련 확장 함수

// toTypedArray() : 컬렉션을 배열로 변환
val list = listOf(1, 2, 3)
val array = list.toTypedArray() // Array<Int>

// toIntArray(), toDoubleArray() 등: 기본 타입 배열로 변환
val primitiveArray = list.toIntArray() // IntArray

// contentToString() : 배열의 내용을 문자열로 변환
println(array.contentToString()) // [1, 2, 3]

 

2. 컬렉션 관련 확장 함수

// getOrDefault() : 키가 없을 때 기본값 반환
val map = mapOf("a" to 1, "b" to 2)
val value = map.getOrDefault("c", 0) // 0

// getOrElse() : 키가 없을 때 람다 실행
val value2 = map.getOrElse("c") { 
    println("키를 찾을 수 없습니다")
    0 
}

// orEmpty() : null일 경우 빈 컬렉션 반환
val nullableList: List<Int>? = null
val safeList = nullableList.orEmpty() // 빈 리스트 반환

 

3. 변환 관련 확장 함수

// map : 각 요소를 변환
val numbers = listOf(1, 2, 3)
val doubled = numbers.map { it * 2 } // [2, 4, 6]

// mapNotNull : null을 제외하고 변환
val mixed = listOf(1, null, 2, null, 3)
val nonNull = mixed.mapNotNull { it } // [1, 2, 3]

// flatten : 중첩 컬렉션을 단일 레벨로
val nested = listOf(listOf(1, 2), listOf(3, 4))
val flat = nested.flatten() // [1, 2, 3, 4]

 

4. 필터링 관련 확장 함수

// filter : 조건에 맞는 요소만 선택
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filter { it % 2 == 0 } // [2, 4]

// filterNot : 조건에 맞지 않는 요소 선택
val odds = numbers.filterNot { it % 2 == 0 } // [1, 3, 5]

// filterNotNull : null이 아닌 요소만 선택
val withNull = listOf(1, null, 2, null, 3)
val noNulls = withNull.filterNotNull() // [1, 2, 3]

 

5. 검색 관련 확장 함수

// find : 조건에 맞는 첫 요소 찾기
val numbers = listOf(1, 2, 3, 4, 5)
val firstEven = numbers.find { it % 2 == 0 } // 2

// firstOrNull : 첫 요소 또는 null
val firstBig = numbers.firstOrNull { it > 10 } // null

// count : 조건에 맞는 요소 개수
val evenCount = numbers.count { it % 2 == 0 } // 2

 

6. 문자열 관련 확장 함수

// capitalize : 첫 글자를 대문자로
val str = "hello"
println(str.capitalize()) // "Hello"

// trimMargin : 여러 줄 문자열의 마진 제거
val text = """
    |First line
    |Second line
""".trimMargin()

// split : 문자열 분할
val parts = "a,b,c".split(",") // [a, b, c]

// removeSurrounding : 앞뒤 문자열 제거
println("<<Hello>>".removeSurrounding("<<", ">>")) // Hello

// replaceFirst : 첫 번째 일치 항목만 교체
println("hello hello".replaceFirst("hello", "hi")) // hi hello

// lines : 줄 단위로 분리
val multiline = """
    First
    Second
    Third
""".trimIndent()
println(multiline.lines()) // [First, Second, Third]

// padStart, padEnd : 문자열 패딩
println("123".padStart(5, '0')) // 00123
println("123".padEnd(5, '0')) // 12300

 

7. 컬렉션 처리 관련 확장 함수

// distinct : 중복 제거
val numbers = listOf(1, 1, 2, 2, 3)
println(numbers.distinct()) // [1, 2, 3]

// chunked : n개씩 묶기
val list = (1..7).toList()
println(list.chunked(3)) // [[1, 2, 3], [4, 5, 6], [7]]

// windowed : 슬라이딩 윈도우
println(list.windowed(3)) // [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]]

// groupBy : 그룹화
val people = listOf(
    Person("Kim", 20),
    Person("Lee", 25),
    Person("Park", 20)
)
val byAge = people.groupBy { it.age }

// associate : Map 생성
val mapped = people.associate { it.name to it.age }

// takeIf : 조건을 만족할 때만 값 반환
val number = 10
val evenNumber = number.takeIf { it % 2 == 0 } // 10
val oddNumber = number.takeIf { it % 2 == 1 } // null

 

8. 널 안전성 관련 확장 함수

// let : null이 아닐 때 코드 블록 실행
val nullableString: String? = "Hello"
nullableString?.let { 
    println(it.length) 
}

// also : 객체를 반환하면서 부가 작업
val numbers = mutableListOf<Int>()
    .also { println("생성된 리스트: $it") }
    .also { it.add(1) }
    .also { println("숫자 추가 후: $it") }

// run : 객체의 함수나 프로퍼티 접근
val str = "Hello"
val length = str.run { 
    uppercase().length 
}

// apply : 객체 설정 후 반환
val person = Person().apply {
    name = "Kim"
    age = 25
}

 

9. 수치 관련 확장 함수

// coerceIn : 범위 내로 제한
val number = 5
println(number.coerceIn(0..10)) // 5
println(number.coerceIn(6..10)) // 6
println(number.coerceIn(0..4)) // 4

// rangeTo : 범위 생성
val range = 1.rangeTo(5) // 1..5

// step : 특정 간격으로 반복
(0..10 step 2).forEach { print(it) } // 0 2 4 6 8 10

 

10. 시퀀스 관련 확장 함수

// asSequence : 지연 평가 시퀀스로 변환
val result = listOf(1, 2, 3)
    .asSequence()
    .map { it * 2 }
    .filter { it > 3 }
    .toList()

// generateSequence : 시퀀스 생성
val fibonacci = generateSequence(Pair(0, 1)) { 
    Pair(it.second, it.first + it.second) 
}.map { it.first }

println(fibonacci.take(6).toList()) // [0, 1, 1, 2, 3, 5]

이번 포스트는 여기서 마치겠습니다.

다음 포스트는, 이번 지식을 활용해서 저번에 풀었던 코딩테스트 문제를 다시 도전하는 글을 올리겠습니다~!

반응형
저작자표시 비영리 변경금지 (새창열림)

'개발 > 모바일' 카테고리의 다른 글

[Coding Test] (5) 프로그래머스 스킬체크 Lv.1  (0) 2025.02.17
[Coding Test] (4) 프로그래머스 스킬체크 Lv.1  (0) 2025.02.17
[Coding Test] (3) 프로그래머스 스킬체크 Lv.1  (0) 2025.02.17
[Coding Test] (2) 이전 문제 다시 풀어보기  (0) 2025.02.13
[Coding Test] (1) 프로그래머스 스킬체크 Lv.1  (0) 2025.02.12
[Kotlin] Flutter로 비교하는 Kotlin & Compose 지식  (0) 2025.02.11
[Kotlin Project] 초성마켓 - 프로젝트 전체적인 구조  (0) 2025.02.11
[Kotlin Project] 초성마켓 - 홈, 퀴즈 페이지 개발  (0) 2025.02.10
'개발/모바일' 카테고리의 다른 글
  • [Coding Test] (3) 프로그래머스 스킬체크 Lv.1
  • [Coding Test] (2) 이전 문제 다시 풀어보기
  • [Coding Test] (1) 프로그래머스 스킬체크 Lv.1
  • [Kotlin] Flutter로 비교하는 Kotlin & Compose 지식
권퓨터
권퓨터
만드는 걸 좋아하는 개발자의 기록. 코드든 글이든, 일단 만들어 봅니다.
  • 권퓨터
    권퓨터: Kwonputer
    권퓨터
  • 티스토리 홈 관리자
  • 전체
    오늘
    어제
    • 분류 전체보기 (557)
      • 개발 (56)
        • 프로젝트 (5)
        • 모바일 (44)
        • 프론트엔드 (0)
        • 백엔드 (2)
        • 인프라 (0)
        • AI · 머신러닝 (4)
      • IT · 테크 (8)
        • 기술 트렌드 (3)
        • 도구 · 생산성 (1)
        • 제품 리뷰 · 추천 (0)
        • 마케팅 · 수익화 (4)
      • 자기계발 (7)
        • 공부법 · 언어 (0)
        • 취업 · 커리어 (7)
      • 아카이브 (486)
        • 일기 (480)
        • 취미 (6)
  • 블로그 메뉴

    • 홈
  • 링크

    • 블로그 이전
  • 공지사항

    • 서브 블로그 => https://kwonputer.com/
  • 인기 글

  • 태그

    서버리스 아키텍처
    python
    클린 아키텍처
    내러티브 게임
    TypeScript
    1인개발
    https://www.kwonputer.shop/
    FACEBOOK광고
    https://github.com/kwongeneral/kortfolio.git
    Single Table Design
    파이썬 기초
    OpenAI GPT
    ai 게임 개발
    AWS CDK
    Prompt Engineering
    aws lambda
    크로스플랫폼
    flutter 개발자
    riverpod
    사이드프로젝트
    flutter
    상태관리
    다국어 블로그
    flutter 면접 질문
    파이썬
    python 기초
    kotlin
    injectable
    Clean Architecture
    dynamodb
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
권퓨터
[Kotlin] 문법 - 반복문 & 배열 & 해시 & 정렬
상단으로

티스토리툴바