안드로이드/Kotlin

[안드로이드][Kotlin] Collections (List, Map, Set)

sinw212 2023. 8. 11. 22:14

개발에 유용한 자료구조와 Collection 함수에 대해 알아보자. Collection에는 크게 List, Map, Set이 있다.

 

1. List (리스트)

List는 데이터가 저장되거나 삭제될 때 순서를 지키는 컬렉션 타입으로, 배열(array)과 달리 크기가 정해져있지 않기 때문에 동적으로 값을 추가할 수 있다.

index를 통해 순차적으로 진행되며, 중간 데이터가 삭제되더라도 나머지 데이터는 순서를 유지한다. 또한 포인터로 불연속적인 메모리에 접근하기 때문에 메모리 관리에 용이하다는 특징이 있다.

 

- 읽기전용 리스트 : listOf()

- 수정가능 리스트 : mutableListOf(), ArrayList<자료형>()

// 읽기 전용 리스트
var scores1 = listOf(값1, 값2, 값3)

scores1.size //리스트 사이즈
scores1.indexOf("값2") //값2의 index
scores1.get(2) //인덱스 2의 값

// 수정 가능 리스트
var scores2 = mutableListOf(값1, 값2, 값3)
var scores2 = ArrayList<자료형>(값1, 값2, 값3)

scores2.add("값4") //값 추가
scores2.remove("값4") //값 삭제
scores2.removeAt(1) //인덱스 1의 값 삭제
scores2.addAll(scores1) //scores1 리스트 추가

의문점) val 로 설정해도 수정이 가능한 이유?

더보기

참조값(주소) 자체는 변하지 않기 때문에  val로 선언되어있더라도 수정이 가능함

(예시(?) _ 철수집의 구성원은 들어갔다 나왔다 하지만, 집 주소가 바뀌지는 않는다.)

val arrayList = arrayListOf<Int>()
arrayList.add(10) //수정 가능
arrayList = arrayListOf<Any>() //Error (참조값이 바뀌기 때문)

 

2. Map (맵)

Map은 Key와 Value가 쌍으로 이루어진 자료형으로, Key는 중복이 될 수 없기 때문에 기존에 존재하는 Key로 값을 저장하면 새로운 값으로 갱신된다.

 

- 읽기전용 맵 : mapOf(“key” to value, “key” to value …)

- 수정가능 맵 : mutableMapOf(“key” to value, “key” to value ...)

//읽기 전용 맵
var scoreInfo1 = mapOf("kor" to 94, "math" to 90, "eng" to 92)
println(scoreInfo1["kor"])

//수정 가능 맵
var scoreInfo2 = mutableMapOf("kor" to 94, "math" to 90)
scoreInfo2["eng"] = 92

//Key, Value 동시 출력
for((key, value) in scoreInfo2) {
    println("${key}, ${value}")
}

- Map의 자료구조 : HashMap, SortedMap, LinkedHashMap

val hashMap = HashMap<Int, String>(1 to "b", 3 to "c", 2 to "a")

println(hashMap.keys) // [1, 3, 2]
println(hashMap.values) // [b, c, a]

println(hashMap.containsKey(2)) // true
println(hashMap.containsValue("d")) // false

println(hashMap.toSortedMap()) // {1="b", 2="a", 3="c"}

 

3. Set (셋)

Set은 중복 데이터 없이 데이터를 관리하는 집합 자료형으로, 여러개의 값이 순서가 정해져 있지 않은 채로 저장된다. 다른 컬렉션들은 요소를 찾는데 집중하는 반면 Set은 요소의 존재여부에 집중한다는 특징이 있다. 

 

- 읽기전용 셋 : setOf()

- 수정가능 셋 : mutableSetOf()

//읽기 전용 셋
var birdSet1 = setOf("닭", "참새", "비둘기")

//수정 가능 셋
var birdSet2 = setOf("닭", "참새")
birdSet2.add("꿩")
birdSet2.remove("꿩")

if(birdSet2.contains("꿩")) println("존재") else println("없음")

- 합집합 / 교집합 / 차집합 : union / intersect / subtract 

var birdSet = setOf("닭", "참새", "비둘기", "물오리")
var flyBirdSet = setOf("참새", "비둘기", "까치")

var unionBirdSet = birdSet.union(flyBirdSet) // 합집합
var intersectBirdSet = birdSet.intersect(flyBirdSet) // 교집합
var subtractBirdSet = birdSet.subtract(flyBirdSet) // 차집합

- Set의 자료구조

HashSet (자바 HashSet 기반) : 순서와 중복된 요소를 무시하며 정렬을 지원하지 않는다는 특징이 있으며 해시값을 통해 값을 찾아내어 검색 속도가 빠르다는 장점이 있다.

SortedSet (자바 TreeSet 기반) : 오름차순으로 정렬된 상태로 반환하며 정렬에 있어 강점이 있는 자료구조이다.

LinkedSet : 각 노드가 다음 연결 노드 포인터를 가지고있어, 자료의 추가와 삭제 있어 강점이 있으며 비어있는 공간을 참조하는 방법으로 효율적인 메모리 관리가 가능하다. 

val hashSet: HashSet<Int> = hashSetOf(1, 3, 2, 4)
println(hashSet) // [2, 1, 3, 4]

val sortedSet: TreeSet<Int> = sortedSetOf(1, 3, 2, 4)
println(sortedSet) // [1, 2, 3, 4]

val linkedSet: LinkedHashSet<Int> = linkedSetOf(1, 3, 2, 4)
println(linkedSet) // [1, 3, 2, 4]

 

4. Collection 함수

- 순회 함수

forEach(), forEachIndexed() : 각 요소에 접근하여 Value 혹은 Index, Value 반환

onEach(), onEachIndexed() : 각 요소에 접근하여 Value 혹은 Index, Value 반환. 수행한 List를 다시 반환

val list = listOf(1, 2, 3, 4)

list.forEach { println( it * 2 ) } // [2, 4, 6, 8]
list.forEachIndexed { index, value -> ... }
val onEachList = list.onEach { println( it * 2 ) } // 2468
val onEachIndexedList = list.onEachIndexed { index, value -> ... }

- 매핑 함수

map() : 모든 요소에 적용할 함수 전달. 함수의 반환값과 각 요소의 Value는 같은 자료형. (인덱스를 포함하는 mapIndexed(), null을 제외하고 특정 식을 수행하는 mapNotNull() 이 있음)

flatMap() : 모든 요소에 적용할 함수 전달. 함수의 반환값은 iterable 객체. 새로운 컬렉션 반환.

groupBy() : 입력한 식에 따라 요소를 그룹화하여 Map으로 변환

val list = listOf(1, 2, 3, 4)
val listWithNull = listOf(1, null, 2, null, 3)

val twiceList = list.map { it * 2 } // [2, 4, 6, 8]
val listWithNotNull = listWithNull.mapNotNull { it?.times(2) } // [2, 4, 6]
val listWithJ = list.flatMap { listOf(it * 3, it * 4) } // [3, 4, 6, 8, 9, 12, 12, 16]
val groupMap = list.groupBy { it % 2 == 0 } // {false=[1, 3, 5], true=[2, 4]}

- 필터링 함수

filter() : 식에 부합하는 요소를 골라내어 컬렉션 반환

filterNot() : 식에 부합하지 않은 요소를 골라내어 컬렉션 반환

filterNotNull() : null을 걸러내어 컬렉션 반환

이외에도, 원하는 자료형을 골라내는 filterIsInstance(), 인덱스를 함께 추출하는 filterIndexed(), 반환하는 filterIndexedTo() 가 있다.

val list = listOf(1, 2, 3, 4)
val listWithNull = listOf(1, null, 2, null, 3)

val twiceList = list.filter { it % 2 == 0 } // [2, 4]
val noTwiceList = list.filterNot { it % 2 == 0 } // [1, 3]
val notNullList = listWithNull.filterNotNull() // [1, 2, 3]