개요
지난 번에 이어 Kotlin
STL 정리하기 2편인 Array & List
에 대한 포스트 입니다.
Array vs List vs MutableList
Kotlin의 배열 및 리스트 형태의 STL에 대해 얘기하기 전에 앞서, 먼저 자료구조 종류 자체를 살펴볼 필요가 있습니다. 다음과 같이 크게 3가지로 구분할 수 있고, 특징은 아래와 같습니다.
Array
- Java의 배열로 컴파일되어
Primitive Type
이다. - 길이가 고정되어 있다.
- 요소들이 메모리 상에 연속적으로 할당되어 있다.
- 인덱스를 이용해 랜덤 요소에 O(1)로 접근할 수 있다.
List
- 길이가 고정되어 있고,
immutable
이다. - 내부적으로 연결리스트이며, 요소들이 메모리 상에 불연속적으로 할당되어 있다.
- 인덱스를 이용해 요소에 접근할 수 있지만 O(N)가 소요된다.
MutableList (ArrayList)
List
타입을 상속한다.- Java의
ArrayList
, C++의vector
와 같이 동작한다. - 요소들이 메모리 상에 연속적으로 할당되어 있다.
- 인덱스를 이용해 랜덤 요소에 O(1)로 접근할 수 있다.
- 요소를 O(1)로 맨 뒤에 추가할 수 있다
- 용량을 동적으로 변경할 수 있고, 요소가 추가됨에 따라 필요 시 자동으로 1.5배 size-up 한다.
- 요소 삭제 및 검색 시 O(N)가 소요된다.
LinkedList
- 요소들이 메모리 상에 불연속적으로 할당되어 있다.
- 특정 요소를 탐색하는 데 O(N)가 소요된다.
- 양 끝에 대한 요소 추가 및 삭제 시 O(1)이 소요된다.
이를 살펴보면 immutable 특성을 띄는 선형 자료구조 중 List
가 Array
에 비해 별 이점을 갖지 못하는 것을 알 수 있습니다. 심지어 비록 Array가 primitive type 이지만, Kotlin 상에서 List
와 거의 동일한 STL을 지원하고 있습니다. 따라서 대부분의 경우에서 immutable 선형 자료구조가 필요하면 Array
, mutable 선형 자료구조가 필요하면 MutableList
를 사용하는 것이 일반적입니다. 그리고 각각 toList()
, toArray()
와 같이 간편한 형변환 메서드를 제공하기 때문에 유연한 코드 작성이 가능합니다.
Array & List
immutable 선형 자료구조인 Array
와 List
의 경우 지원하는 STL이 거의 같기 때문에 List
를 기준으로 통합하여 작성하였습니다.
size
리스트의 길이를 반환합니다.
1 |
|
1 |
|
contains
특정 요소가 포함되어 있는지 체크합니다.
1 |
|
1 |
|
containsAll
특정 리스트에 있는 모든 요소들이 해당 리스트에 포함되어 있는지 체크합니다.
1 |
|
1 |
|
get
특정 인덱스의 요소를 반환합니다.
1 |
|
1 |
|
indexOf
특정 요소의 인덱스를 반환합니다.
1 |
|
1 |
|
isEmpty & isNotEmpty
리스트가 비어있는지 체크합니다.
1 |
|
1 |
|
subList
리스트의 부분 리스트를 반환합니다.
1 |
|
1 |
|
indices
리스트의 인덱스 범위를 반환합니다.
1 |
|
1 |
|
lastIndex
리스트의 마지막 인덱스를 반환합니다.
1 |
|
1 |
|
all
리스트의 모든 요소들이 특정 조건을 만족하는지 체크합니다.
1 |
|
1 |
|
any
리스트의 요소들 중 하나라도 특정 조건을 만족하는지 반환합니다.
1 |
|
1 |
|
associate
리스트의 요소들로 key
, value
를 지정해 map
형태로 반환합니다.
1 |
|
1 |
|
associateBy
associate
와 동일하되, key
를 지정하고 value
는 요소값으로 고정합니다.
1 |
|
1 |
|
associateWith
associate
와 동일하되, value
를 지정하고 key
는 요소값으로 고정합니다.
1 |
|
1 |
|
binarySearch
리스트에서 이진 탐색으로 특정 요소의 인덱스를 탐색하여 반환합니다.
1 |
|
1 |
|
binarySearchBy
binarySearch
와 동일하되, 키 값을 별도로 지정합니다.
1 |
|
1 |
|
chunked
리스트를 특정 갯수만큼의 요소로 쪼갠 리스트들의 리스트로 반환합니다.
1 |
|
1 |
|
count
리스트에서 특정 조건을 만족하는 요소들의 갯수를 반환합니다.
1 |
|
1 |
|
distinct
리스트에서 중복 요소를 제거한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
distinctBy
distinct
와 동일하되, 키 값을 지정합니다.
1 |
|
1 |
|
drop
리스트에서 첫 n
개의 요소를 제거한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
dropWhile
리스트의 앞에서부터 특정 조건을 만족하지 않는 요소가 등장할 때 까지 요소를 제거한 리스트를 반환합니다.
1 |
|
1 |
|
dropLast
drop
과 동일하나, 뒤에서부터 진행합니다.
1 |
|
1 |
|
dropLastWhile
dropWhile
과 동일하나, 뒤에서부터 진행합니다.
1 |
|
1 |
|
filter
리스트에서 특정 조건을 만족하는 요소들로만 이루어진 새로운 리스트를 반환합니다.
1 |
|
1 |
|
filterIndexed
filter
와 동일하나, 인자로 index를 포함합니다.
1 |
|
1 |
|
filterNot
filter
와 동일하나, 조건을 반전합니다.
1 |
|
1 |
|
find
리스트에서 특정 조건을 만족하는 첫번째 요소를 반환합니다.
1 |
|
1 |
|
findLast
리스트에서 특정 조건을 만족하는 마지막 요소를 반환합니다.
1 |
|
1 |
|
first
리스트의 첫번째 요소롤 반환하거나, find
와 동일하게 동작합니다.
1 |
|
1 |
|
flatten
중첩 리스트를 단일 리스트로 펼친 새로운 리스트를 반환합니다.
1 |
|
1 |
|
flatMap
flatten
와 동일하되, 요소를 변경합니다.
1 |
|
1 |
|
flatMapIndexed
flatMap
과 동일하되, 인자로 index를 포함합니다.
1 |
|
1 |
|
fold
초기값을 설정하여 리스트 요소들에 특정 연산을 순차적으로 누적한 값을 반환합니다.
1 |
|
1 |
|
foldRight
fold
와 동일하되, 역순으로 누적합니다.
1 |
|
1 |
|
foldIndexed
fold
와 동일하되, 인자로 index를 포함합니다.
1 |
|
1 |
|
foldRightIndexed
foldIndexed
와 동일하되, 역순으로 누적합니다.
1 |
|
1 |
|
forEach
리스트의 각 요소에 대해 반복문을 실행합니다.
1 |
|
1 |
|
forEachIndexed
forEach
와 동일하되, 인자로 index를 포함합니다.
1 |
|
1 |
|
groupBy
리스트의 요소들을 특정 key
로 grouping 한 map
을 반환합니다.
1 |
|
1 |
|
ifEmpty
리스트가 비어있을 때, 기본값을 반환합니다.
1 |
|
1 |
|
joinToString
리스트의 요소들을 문자열로 변환하여 이어붙인 문자열을 반환합니다.
1 |
|
1 |
|
last
리스트의 마지막 요소를 반환하거나, findLast
와 동일하게 동작합니다.
1 |
|
1 |
|
map
리스트의 각 요소들에 특정 변환을 수행한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
mapIndexed
map
과 동일하나, 인자로 index를 포함합니다.
1 |
|
1 |
|
maxOf
리스트의 요소 중 지정한 키 값이 최대인 키 값을 반환합니다.
1 |
|
1 |
|
minOf
리스트의 요소 중 지정한 키 값이 최소인 키 값을 반환합니다.
1 |
|
1 |
|
minus
리스트의 요소 중 특정 요소 또는 특성 리스트에 포함된 요소와 일치하는 요소를 제외한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
minus
리스트에 특정 요소 및 리스트를 이어붙인 새로운 리스트를 반환합니다.
1 |
|
1 |
|
partition
리스트의 요소들을 특정 기준으로 분류한 2개의 리스트 Pair
로 반환합니다.
1 |
|
1 |
|
reversed
리스트의 순서를 반전한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
slice
리스트를 특정 범위만큼 자른 리스트를 반환합니다.
1 |
|
1 |
|
sorted
리스트를 정렬한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
sortedDescending
리스트를 역순으로 정렬한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
sortedBy
리스트를 특정 값을 기준으로 정렬한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
sortedBy
리스트를 특정 값을 기준으로 역순 정렬한 새로운 리스트를 반환합니다.
1 |
|
1 |
|
sortedWith
Comparator
를 이용해 정렬합니다. 주로 복합적인 정렬 조건일 때 사용합니다.
1 |
|
1 |
|
sumOf
리스트 요소의 특정 값의 합을 반환합니다.
1 |
|
1 |
|
take
리스트 앞에서부터 n
개의 요소를 포함하는 새로운 리스트를 반환합니다.
1 |
|
1 |
|
takeWhile
리스트 앞에서부터 특정 조건을 만족하지 않는 요소가 등장하기 전까지의 요소를 갖는 새로운 리스트를 반환합니다.
1 |
|
1 |
|
takeLast
take
와 동일하되, 뒤에서부터 포함합니다.
1 |
|
1 |
|
takeLastWhile
takeWhile
과 동일하되, 뒤에서부터 포함합니다.
1 |
|
1 |
|
union
다른 리스트와 병합하여 중복 요소를 제거한 set
을 반환합니다.
1 |
|
1 |
|
zip
두 리스트를 각 인덱스의 요소 별로 합쳐 하나의 리스트로 반환합니다. 반환되는 리스트의 길이는 두 리스트의 길이 중 더 작은 값을 따릅니다.
1 |
|
1 |
|
두 리스트의 각 인덱스 별 요소를 Pair
로 갖는 하나의 리스트를 반환합니다.
1 |
|
1 |
|
unzip
Pair
를 요소로 갖는 하나의 리스트를 각각 Pair
의 first와 second 값을 요소로 하는 두 개의 리스트로 이루어진 Pair
를 반환합니다.
1 |
|
1 |
|
zipWithNext
리스트에서 인접한 모든 쌍을 Pair
로 갖는 요소들로 이루어진 리스트를 반환합니다.
1 |
|
1 |
|
MutableList
MutableList
의 경우에는 List
를 상속하기 때문에 기본적으로 위에서 언급한 STL을 모두 사용할 수 있습니다. 그 외에 내부 요소를 직접 변경할 수 있는 아래와 같은 STL들을 추가적으로 지원합니다.
add
리스트의 끝 또는 특정 인덱스에 요소를 추가합니다.
1 |
|
1 |
|
addAll
리스트의 끝 또는 특정 인덱스에 요소들을 추가합니다.
1 |
|
1 |
|
clear
리스트를 비웁니다.
1 |
|
1 |
|
remove
리스트에서 특정 요소를 앞에서 하나 제거합니다.
1 |
|
1 |
|
removeAll
리스트에서 특정 조건을 만족하는 요소들을 모두 제거합니다.
1 |
|
1 |
|
removeAt
리스트에서 특정 인덱스의 요소를 제거합니다.
1 |
|
1 |
|
removeFirst
리스트의 가장 앞 요소를 제거합니다. 존재하지 않을 시 예외를 발생시킵니다.
1 |
|
1 |
|
removeLast
리스트의 가장 뒤 요소를 제거합니다. 존재하지 않을 시 예외를 발생시킵니다.
1 |
|
1 |
|
retainAll
리스트에서 특정 조건을 만족하는 요소들만 남겨둡니다.
1 |
|
1 |
|
set
리스트에서 특정 인덱스의 요소를 변경합니다.
1 |
|
1 |
|
plusAssign
리스트에 요소를 연산자로 추가합니다.
1 |
|
1 |
|
minusAssign
리스트에 요소를 연산자로 제거합니다.
1 |
|
1 |
|
그 외에 reversed()
와 sorted()
같이 수동태로 쓰여진 메서드와 같은 경우, 능동태로 변환한 reverse()
와 sort()
로 MutableList
에서 사용 가능합니다. 능동태 메서드의 경우에는 변환 시킨 리스트를 반환할 뿐만 아니라, mutable 답게 원본 리스트까지 실제로 수정한다는 차이점이 있습니다.
Numbers
그리고 Int
및 Double
과 같이 Numbers 타입을 요소로 갖는 리스트의 경우, 다음과 같은 확장 함수를 이용할 수 있습니다.
List<T>.max()
: 리스트의 최댓값 반환List<T>.min()
: 리스트의 최솟값 반환List<T>.sum()
: 리스트의 누적합 반환List<T>.average()
: 리스트의 평균값 반환
응용
리스트에서 인접한 중복 요소 제거
1 |
|
1 |
|
마치며
Kotlin은 리스트에 대한 STL이 굉장히 풍부한 편이기 때문에, 종종 알고리즘 문제 해결 사이트에서 복잡한 문제에 대해 한 줄 짜리 답안을 심심치 않게 볼 수 있습니다. 비록 PS에서 답안 코드의 길이가 중요하지는 않습니다만, 문제 풀이 속도에는 상당히 큰 영향을 미치므로 리스트에 대한 STL 학습은 굉장히 중요한 요소라고 생각합니다.
- Post link: https://blog.yjyoon.dev/kotlin/2023/03/14/kotlin-02/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.