일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- multipart
- gradle plugin
- DataBinding
- Navigation
- studywithme
- layout_constrainedWidth
- Android
- NumberPIcker
- DialogFragment
- ThreeTen Backport
- RecyclerView
- findNavController
- layout_constrainedHeight
- Collections Function
- Room
- http
- BottomSheetDialogFragment
- log
- Popup menu background color
- 화면 회전
- kotlin
- Load failed
- Lifecycle
- 기기고유값
- todo
- WorkManager
- json
- 생명주기
- SSAID
- Retrofit2
- Today
- Total
chacha's
컬렉션(Collections) 본문
목차
Kotlin In Action - 책
과 아래에 링크된 게시글을 참고하여 작성한 게시글입니다.
컬렉션에 대해 공부하기 위한 게시글입니다.
👉 원문을 보는 것을 추천드립니다!!
📌 컬렉션을 보기 전에, 컬렉션에 들어갈 수 있는 Basic types을 봅시다!
Collections의 종류
Kotlinloang.org/docs
코틀린의 Collection은 Java와 매우 유사하지만, Mutable과 Immutable을 구분하여 지원한다는 점이 다릅니다.
- List는 데이터를 저장하거나 삭제할 때 순서를 지키는 컬렉션입니다. [ C++의 Vector와 유사하다고 생각하면 될 것 같습니다. ]
- Set은 동일한 아이템이 없는 컬렉션입니다. 따라서 Set의 아이템들은 순서가 특별히 정해져 있지 않습니다. Set의 기본 구현은 LinkedHashSet입니다.
- Map은 Key-Value Pair(or entries)를 저장하는 컬렉션입니다. key 값은 유일하기 때문에 key가 동일한 element를 추가할 수 없습니다. Map의 기본 구현은 LinkedHashMap입니다.
Kotlin의 컬렉션은 제네릭(Generic)으로 구현이 되어 있기 때문에 다양한 타입으로 사용할 수 있습니다.
Kotlin의 컬렉션은 기본적으로 Mutable과 Immutable을 별개로 지원합니다.
- 그냥 List/Set/Map으로 생성할 경우, 읽기 전용(read-only)로 생성되기 때문에 삽입/삭제가 불가능합니다.
- Mutable한 컬렉션으로 변경한다고 해서 var로 선언할 필요는 업습니다. 요소를 삽입/삭제를 한다고 해서 참조가 변경되지 않습니다. 또한 이미 val로 선언된 컬렉션을 다시 할당하려고 하면 컴파일 오류가 발생합니다.
val numbers = mutableListOf("one", "two", "three", "four")
numbers.add("five")
// 아래는 컴파일 오류가 발생합니다.
// numbers = mutableListOf("six", "seven")
💡 Array? ArrayList? List?
List는 Array와 매우 유사합니다. 하지만 Array의 크기는 초기화 시점과 동시에 정의되며 변경되지 않습니다. 하지만 List는 사전적으로 정의된 크기를 가지지 않습니다. 따라서 요소(element)를 추가, 업데이트, 삭제하는 등의 쓰기 연산(write operation)을 통해 리스트의 크기를 변경할 수 있습니다.
# 📌 Array 선언과 ArrayList 선언의 차이 [접은 글]
/* Array */
val x: IntArray = intArrayOf(1, 2, 3)
val arr = IntArray(5) // [0, 0, 0, 0, 0]
val arr = IntArray(5) { 42 } // [42, 42, 42, 42, 42]
var arr = IntArray(5) { it * 1 } // [0, 1, 2, 3, 4]
var arr = intArrayOf(1, 2, 3, 4) // [1, 2, 3, 4]
var arr = Array(10, { i -> 1 }) // [ 1, 1, ... , 1 ]
val intArr: Array<Int> = arrayOf(1, 2, 3) // [1, 2, 3]
/* ArrayList */
val list = arrayListOf(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]
val list = arrayListOf<Int>()
list.addAll(listOf(1, 2, 3)) // [1, 2, 3]
# 📌 Array 선언과 ArrayList 선언의 차이 [닫기]
# 📌 2차원 배열 생성하기
var matrix2D: Array<IntArray> = Array(height) { IntArray(width) }
var matrix3D = Array(5){ Array(5){ Array(5){1} } }
# 📌 2차원 배열 생성하기
📚 Collection 함수의 종류
1️⃣ Collection 생성을 위한 함수 종류 ( Creation )
Kotlin의 Collection 함수
아래의 코드들은 코틀린에서 컬렉션을 인스턴스화 하는 함수 목록입니다.
// 비어있는 컬렉션
emptyList, emptyMap, emptySet
// 읽기 전용 컬렉션
listOf, mapOf, setOf
// 변경 가능한 컬렉션
mutableListOf, mutableMapOf, mutableSetOf, arrayListOf
// 다른 소스를 첨가할 수 있는 빌드 컬렉션
buildList, buildMap, buildSet
// Linked 컬렉션
linkedMapOf, linkedSetOf
// 정렬된 컬렉션
sortedMapOf, sortedSetOf
// Hash 컬렉션
hashMapOf, hashSetOf
// 프로그래밍 방식으로 컬렉션 만들기
List, MutableList, Iterable
# 📌 Map 생성하기
val numbersMap = mapOf<String, String>("1" to "one", "2" to "two", "3" to "three")
val numbersMap2 = mapOf(Pair("1", "one"), Pair("2", "two"), Pair("3", "three"))
# 📌 Map 생성하기
linkedSetOf과 hashSetOf의 차이
What's the different between linkedSetOf and hashSetOf? - stack overflow
linkedSetOf
는 LinkedHashSet
을 반환하고 hashSetOf
는 HashSet
을 반환합니다.
🤔 그렇다면 LinkedHashSet
은 HashSet
의 차이점은 무엇일까요?
LinkedHashSet
은 삽입될 때의 순서를 유지하는 컬렉션입니다. 삽입 순서를 따로 저장합니다. 반면에 HashSet
은 요소의 순서를 유지하지 않습니다. 요소의 순서에 대해 아무것도 알려주지 않으므로, 동일한 수의 요소를 저장할 때 더 적은 메모리를 필요로 합니다. 이러한 특징은 LinkedHashMap
,HashMap
도 동일합니다. ( Kotlin playground )
/* LinkedHashSet */
val set: LinkedHashSet<Int> = linkedSetOf(1, 3, 2)
println(set) // [1, 3, 2]
set.remove(3)
set += listOf(5, 4)
println(set) // [1, 2, 5, 4]
/* HashSet */
val hashSet: HashSet<Int> = hashSetOf(1, 3, 2)
println(hashSet) // [1, 2, 3]
hashSet.remove(3)
hashSet += listOf(5, 4)
println(hashSet) // [1, 2, 4, 5]
위의 예제만 참고하면 HashSet이 SortedSet과 무엇이 다른가 싶습니다. 하지만 HashSet
은 요소를 정렬하지 않습니다. 아래의 코드를 통해 이를 확인할 수 있습니다. ( Kotlin playground )
/* LinkedHashSet */
val linkedHashSet = linkedSetOf("aaa","bbb","ccc")
println(linkedHashSet) // [aaa, bbb, ccc]
linkedHashSet.remove("ccc")
linkedHashSet += listOf("ddd","zzz")
println(linkedHashSet) // [aaa, bbb, ddd, zzz]
/* HashSet */
val hashSet = hashSetOf("aaa","bbb","ccc")
println(hashSet) // [aaa, ccc, bbb]
hashSet.remove("ccc")
hashSet += listOf("ddd","zzz")
println(hashSet) // [aaa, bbb, zzz, ddd]
3️⃣ Collection 타입 변경 ( Change )
컬렉션을 다른 타입으로 변경하려고 시도하는 함수 목록입니다.
toIntArray()
다른 타입의 새 컬렉션으로 변환하는 함수 목록입니다.
// 배열 타입으로 복사
toBooleanArray, toByteArray, toCharArray, toDoubleArray, toFloatArray, toIntArray, toLongArray, toShortArray, toTypedArray, toUByteArray, toUIntArray, toULongArray, toUShortArray
// 읽기 전용 컬렉션으로 복사
toList, toMap, toSet
// 변경 가능한 컬렉션으로 복사
toMutableList, toMutableMap, toMutableSet, toHashSet
// 정렬된 컬렉션으로 복사
toSortedMap, toSortedSet
// 엔트리를 쌍으로 변환
toPair
// 맵을 프로퍼티로 변환
toProperties
- Example Code
// 새로운 복사
val uIntArray = UIntArray(3) { 1U }
val toIntArray = uIntArray.toIntArray()
toIntArray[1] = 2
println(toIntArray.toList()) // [1, 2, 1]
println(uIntArray.toList()) // [1, 1, 1]
asIntArray()
원래 값에 대한 참조가 있는 다른 타입으로 변환하는 함수 목록입니다.
// 배열 타입으로 변환
asByteArray, asIntArray, asLongArray, asShortArray, asUByteArray, asUIntArray, asULongArray, asUShortArray,
// 컬렉션 타입으로 변환. list와 sequestion에 대한 비교는 여기서 확인할 수 있습니다.
asIterable, asList, asSequence
// 인덱스가 있는 반복자로 변환
withIndex
// 사용자가 지정한 기본값을 사용하여 Map으로 변환
withDefault
- Example Code
// 참조 복사
val uIntArray = UIntArray(3) { 1U }
val asIntArray = uIntArray.asIntArray()
asIntArray[1] = 2
println(asIntArray.toList()) // [1, 2, 1]
println(uIntArray.toList()) // [1, 2, 1]
5️⃣ Collection 항목에서 무언가를 생성 ( Conclude )
📁 Collection과 Sequence의 차이점
Sequences - Kotlinlang
Kotlin - Collections와 Sequences의 차이점 - codechacha
를 참고하여 작성하였습니다.
👆 codechacha님 게시글에는 Kotlin Collections와 Java Stream의 차이점, Kotlin에서의 Stream 등추가로 참고하면 좋을 내용이 많이 있습니다.
Collections
는 조급한 계산법(Eager evalution)으로 동작합니다. "조급한 계산법"이란? 수행해야 할 연산이 있으면 미루지 않고 바로 처리하는 방식을 말합니다.
Sequences
는 느긋한 계산법(Lazy evaluation)으로 동작합니다. "느긋한 계산법"이란? 가능한 코드의 수행을 미루고, 어쩔 수 없이 연산이 필요한 순간에 연산을 수행하는 방식을 말합니다.
따라서, Collections와 Sequences는 동일한 결과 값을 출력할 수 있지만 수행하는 과정이 다릅니다. List 요소의 개수가 매우 적다면 Collections가 빠를 수 있지만, List의 개수가 많다면 Sequences가 성능 측면에서 유리할 수 있습니다.
- Collections 예제
val words = "The quick brown fox jumps over the lazy dog".split(" ")
val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.take(4)
println("Lengths of first 4 words longer than 3 chars:")
println(lengthsList)
/* 결과 값 */
filter: The
filter: quick
filter: brown
filter: fox
filter: jumps
filter: over
filter: the
filter: lazy
filter: dog
length: 5
length: 5
length: 5
length: 4
length: 4
Lengths of first 4 words longer than 3 chars:
[5, 5, 5, 4]
- Sequences 예제
val words = "The quick brown fox jumps over the lazy dog".split(" ")
//convert the List to a Sequence
val wordsSequence = words.asSequence()
val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.take(4)
println("Lengths of first 4 words longer than 3 chars")
// terminal operation: obtaining the result as a List
println(lengthsSequence.toList())
/* 결과 값 */
Lengths of first 4 words longer than 3 chars
filter: The
filter: quick
length: 5
filter: brown
length: 5
filter: fox
filter: jumps
length: 5
filter: over
length: 4
[5, 5, 5, 4]
take(4)
는 4개의 아이템만 가져오면 되기 때문에, 이를 충족하면 이후 아이템에 대해서는 filter()
를 수행할 필요가 없습니다. 이러한 부분 때문에, Collections 보다 연산이 빨리 끝날 수 있습니다.
End
'Kotlin' 카테고리의 다른 글
[ Kotlin ] 코틀린에서 Queue 사용하기 (0) | 2021.12.11 |
---|