일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스피너
- video caching
- exoplayer cache
- ListAdapter
- 유튜브
- android custom view
- Zsh
- ChatGPT
- 안드로이드
- ktor client
- android ktor
- 시행착오
- kotlin collection
- doc2vec
- map
- ListAdapter DiffUtil
- android exoplayer
- AWS EC2
- FastAPI
- android
- 유튜브 요약
- getChangePayload
- kotlin list
- build with ai
- ktor api call
- ExoPlayer
- llm
- DiffUtil.ItemCallback
- list map
- Python
- Today
- Total
버튼 수집상
[Kotlin] List.map 파헤치기 본문
얼마 전에 ListAdapter의 DiffUtil을 쓰는 법에 대한 글을 썼었다.
[안드로이드] ListAdapter DiffUtil 제대로 쓰기 - 1
배경 리사이클러뷰에서 부분적으로 UI를 업데이트할 때 (ex: 찜하기) 업데이트한 리스트를 submitList()로 세팅해도 DiffUtil이 제대로 돌아가지 않는 경우가 있었다. 리스트 변경사항을 제대로 감지하
collectingbuttons.tistory.com
글 1편은 ListAdapter 보다 List.map()에 대해 적었다.
그런데 위 글을 적은 후에도 여전히 헷갈리는 부분이 있어서 다시 정리해봤다.
코틀린 Collections 파일에서 map 함수의 시그니처를 보자.
/**
* Returns a list containing the results of applying the given [transform] function
* to each element in the original collection.
*
* @sample samples.collections.Collections.Transformations.map
*/
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> { /** 구현부 생략 **/ }
map은 T타입의 Iterable 객체를 받아서 R타입 리스트로 리턴한다.
인자로 받아온 Transform 함수를 람다식으로 표현한다.
var testList : List<Int> = listOf(1,2,3)
var newList : List<String> = testList.map { it -> "${it*100}"}
println(testList)
println(newList)
// [1, 2, 3]
// [100, 200, 300]
위 예시에서
람다식의 it 이 Transform 함수의 인자, T타입 객체이고
람다식의 "${it*100}" 이 Tranform 함수의 리턴값, R타입 객체다.
map 블럭의 마지막 줄에 리턴값 적는 것을 잊지 않아야 한다.
안 그러면 Unit을 반환한다.
map 블럭 안에서 원본 요소를 변경하려고 하면 에러가 뜬다.
var testList : List<Int> = listOf(1,2,3)
// Error : Val cannot be reassigned
var newList : List<Int> = testList.map {
it *= 100
it
}
String, Int와 같은 Primitive 타입 데이터는 한 번 생성되면 값을 변경할 수 없기 때문이다. (Immutable)
그렇다면 오브젝트 타입 리스트를 만들어보자.
data class SimpleObject(
var name: String,
var isChecked: Boolean = false
){
override fun toString(): String {
return "$name ($isChecked)"
}
}
fun main() {
var testList : List<SimpleObject> = listOf(
SimpleObject("Obj1"),
SimpleObject("Obj2")
)
var newList : List<SimpleObject> = testList.map {
it.isChecked = true
it
}
println(testList)
println(newList)
}
// [Obj1 (true), Obj2 (true)]
// [Obj1 (true), Obj2 (true)]
SimpleObject의 isChecked는 값을 변경할 수 있다. (Mutable var)
그래서 람다식 안에서 원본 요소에 직접 접근해서 값을 수정했더니, 원본 리스트도 변경됐다.
리스트의 요소의 객체가 바뀌지 않았기 때문에 얕은 복사가 된 것이다.
객체 주소값을 비교할 땐 equals()나 hashCode()을 사용한다.
원본 리스트에 영향받지 않으려면 map 새로운 객체를 생성해서 리턴한다.
fun main() {
var testList : List<SimpleObject> = listOf(
SimpleObject("Obj1"),
SimpleObject("Obj2")
)
var newList : List<SimpleObject> = testList.map {
it.copy().apply { isChecked = true }
}
println(testList)
println(newList)
}
// [Obj1 (false), Obj2 (false)]
// [Obj1 (true), Obj2 (true)]
결론
Primitive 타입 리스트는 map 블럭 안에서 요소의 값을 변경할 수 없다. 고로 원본 리스트가 변경될 여지가 없다.
참조타입 리스트는 map 블럭 안에서 요소 객체를 새로 생성하지 않고 값을 변경하면 원본도 같이 변경된다.
'TIL - Kotlin' 카테고리의 다른 글
[Kotlin] List.filter 파헤치기 (0) | 2024.04.16 |
---|---|
[Kotlin] RxJava의 mergeDelayError를 Coroutine Flow로 만들기 Coroutine Flow merge (0) | 2024.01.09 |
[Kotlin] 유용한 Collection 함수 (0) | 2023.07.04 |
[Kotlin] 코틀린 코드 스니펫 돌려보기 (0) | 2023.06.26 |
[Kotlin] 유용한 List 고차함수 (0) | 2023.04.18 |