컬렉션의 고차 함수들
1. map
- 정의: 컬렉션의 각 요소를 변환하여 새로운 컬렉션을 반환합니다.
- 용도: 리스트의 요소들을 다른 값으로 변환할 때 사용.
| |
2. filter
- 정의: 주어진 조건에 맞는 요소들만 필터링하여 새로운 컬렉션을 반환합니다.
- 용도: 리스트에서 특정 조건을 만족하는 요소들만 남기고 싶을 때 사용.
| |
3. reduce
- 정의: 컬렉션의 모든 요소를 누적하여 단일 값을 반환합니다.
- 용도: 리스트에서 값을 축적하거나 합산할 때 사용.
| |
acc는 누적된 값이고,number는 리스트의 현재 요소입니다.
4. fold
- 정의:
reduce와 유사하지만, 초기값을 지정할 수 있습니다. - 용도: 초기값과 함께 누적 연산을 해야 할 때 사용.
| |
- 초기값으로 1을 제공했고, 이를 기반으로 리스트의 각 요소를 곱하여 누적합니다.
5. forEach
- 정의: 컬렉션의 각 요소에 대해 주어진 동작을 수행합니다. 반환값은 없습니다.
- 용도: 컬렉션의 요소를 순회하면서 작업을 수행할 때 사용.
| |
6. flatMap
- 정의: 각 요소를 변환하고, 변환된 결과들을 평탄화하여 하나의 리스트로 반환합니다.
- 용도: 리스트의 리스트를 하나의 리스트로 합치고 싶을 때 사용.
| |
7. groupBy
- 정의: 컬렉션의 요소를 주어진 키로 그룹화하여 Map을 반환합니다.
- 용도: 리스트의 요소를 특정 조건에 따라 그룹화할 때 사용.
| |
8. partition
- 정의: 조건에 따라 컬렉션을 두 개의 리스트로 나눕니다. 조건을 만족하는 요소는 첫 번째 리스트에, 그렇지 않은 요소는 두 번째 리스트에 담깁니다.
- 용도: 리스트를 조건에 맞게 둘로 나눌 때 사용.
| |
9. take / takeWhile
take: 처음부터 주어진 숫자만큼의 요소를 가져옵니다.takeWhile: 조건을 만족하는 동안만 요소를 가져옵니다.
| |
10. zip
- 정의: 두 개의 컬렉션을 병합하여 쌍(pair)의 리스트를 만듭니다.
- 용도: 두 리스트를 쌍으로 묶고 싶을 때 사용.
| |
11. any / all / none
any: 하나라도 조건을 만족하는 요소가 있으면true를 반환합니다.all: 모든 요소가 조건을 만족하면true를 반환합니다.none: 하나도 조건을 만족하지 않으면true를 반환합니다.
| |
12. find / firstOrNull
find: 조건을 만족하는 첫 번째 요소를 반환합니다.firstOrNull: 조건을 만족하는 요소가 없으면null을 반환합니다.
| |
13. groupingBy / eachCount
- Python의
Counter기능
| |
14. groupBy와 groupingBy의 차이점
| groupBy | groupingBy | |
|---|---|---|
| 결과 | 즉시 그룹화된 맵을 반환 (Map<K, List<V>>) | 지연 계산을 위한 Grouping 객체 (Grouping<K, T>) |
| 동작 방식 | 그룹화와 동시에 결과를 반환 | 추가 처리가 필요, eachCount, fold, reduce 등 |
| 사용 시기 | 그룹화된 결과가 즉시 필요한 경우 | 그룹화 후 추가적인 처리나 지연 계산이 필요한 경우 |
| 예시 | list.groupBy { it } | list.groupingBy { it }.eachCount() |
정렬 기준이 여러 개일 때 정렬
Kotlin에서 여러 기준으로 정렬하려면 sortedWith를 사용하고, 각 기준에 맞는 Comparator를 정의할 수 있습니다.
정렬 기준을 여러 개 지정할 때는 주로 compareBy와 thenBy를 사용해 우선순위를 설정합니다.
문제 예시:
만약 리스트가 List<Triple<Int, Int, Int>> 형식이고,
각 요소에 대해 2번 요소(세 번째 값)를 우선적으로 비교하고, 그 다음으로 0번 요소(첫 번째 값), 마지막으로 1번 요소(두 번째 값)를 기준으로 정렬한다고 가정해 보겠습니다.
코드 예시:
| |
- Kotlin에서
thenBy는 다중 정렬 기준을 사용할 때, 첫 번째 기준이 동일한 경우 두 번째 정렬 기준을 적용하기 위해 사용됩니다.- 즉, 첫 번째 기준에서 비교가 끝나지 않았을 때, 추가적인 비교 기준을 설정하는 역할을 합니다.
thenByDescending도 가능
heap: PriorityQueue
PriorityQueue는 기본적으로 최소 힙(min-heap)으로 동작하며, 최대 힙(max-heap)을 구현하려면 커스텀 비교 함수를 제공해줘야 한다.
최소 힙 (Min-Heap) 사용
PriorityQueue는 기본적으로 최소 힙으로 구현되어 있으며, 값을 삽입할 때 자동으로 우선 순위에 맞게 정렬되어 가장 작은 값이 우선 처리된다.
| |
최대 힙 (Max-Heap) 사용
최대 힙은 기본적으로 지원하지 않기 때문에, 커스텀 비교자를 설정해 값을 큰 순서대로 처리하도록 할 수 있다.
Comparator를 이용해 값을 반대로 비교하면 최대 힙을 구현할 수 있다.
| |
사용자 정의 객체를 힙에 사용
만약 힙에 사용자 정의 객체를 저장하고 싶다면, 해당 객체의 우선순위를 지정할 수 있도록 Comparator를 정의해야 한다.
예를 들어, 객체에 포함된 특정 속성 값을 기준으로 힙을 구성할 수 있다.
| |
PriorityQueue의 기능들
1. 생성자
PriorityQueue(): 기본 생성자로 빈 우선순위 큐를 생성한다.PriorityQueue(initialCapacity: Int): 지정한 초기 용량을 가진 우선순위 큐를 생성한다.PriorityQueue(comparator: Comparator<in E>): 커스텀Comparator를 제공해 우선순위를 정의할 수 있다. 이를 통해 최대 힙을 구현할 수 있다.
2. 주요 함수
2.1. 삽입과 삭제
add(element: E): Boolean: 우선순위 큐에 요소를 추가하고, 성공하면true를 반환한다. 큐가 가득 찬 경우 예외를 던질 수 있다.1 2 3 4val pq = PriorityQueue<Int>() pq.add(10) pq.add(5) pq.add(20)offer(element: E): Boolean:add()와 동일하게 요소를 큐에 추가하지만 예외를 던지지 않는다. 성공 여부를Boolean으로 반환한다.1pq.offer(15)poll(): E?: 우선순위가 가장 높은(가장 작은) 요소를 제거하고 반환한다. 큐가 비어있으면null을 반환한다.1val minValue = pq.poll()remove(element: E): Boolean: 특정 요소를 큐에서 제거하고, 성공하면true를 반환한다. 큐에 해당 요소가 없으면false를 반환한다.1val isRemoved = pq.remove(5)
2.2. 조회
peek(): E?: 큐에서 우선순위가 가장 높은 요소를 제거하지 않고 반환한다. 큐가 비어 있으면null을 반환한다.1val topValue = pq.peek()element(): E:peek()와 동일하게 가장 높은 우선순위의 요소를 반환하지만, 큐가 비어있으면 예외(NoSuchElementException)를 던진다.1val firstElement = pq.element()
2.3. 상태 확인
isEmpty(): Boolean: 큐가 비어 있는지 여부를 반환한다.size(): Int
2.4. 기타 함수
clear(): 큐의 모든 요소를 제거한다.contains(element: E): Boolean: 특정 요소가 큐에 포함되어 있는지 확인하고true나false를 반환한다toArray(): Array<Any?>: 큐의 모든 요소를 배열로 반환한다.1val array = pq.toArray()
deque: ArrayDeque, LinkedList
Kotlin에서는 직접적으로 Deque(양방향 큐) 에 대한 클래스를 제공하지 않습니다.
하지만 Java의 Deque 인터페이스와 그 구현체인 ArrayDeque 또는 LinkedList 를 Kotlin에서 사용할 수 있습니다.
Deque는 양쪽에서 삽입과 삭제가 가능한 자료구조로, 스택이나 큐와 같은 동작을 모두 수행할 수 있습니다.
1. ArrayDeque 사용
Java의 ArrayDeque 은 크기 조정이 가능한 배열 기반의 Deque 구현체로, 가변 크기의 양방향 큐입니다.
기본 사용법:
| |
2. LinkedList 사용
또 다른 Deque 구현체는 LinkedList 입니다. LinkedList는 노드 기반의 자료구조로, Deque와 같은 양방향 큐로 사용할 수 있습니다.
기본 사용법:
| |
3. Deque의 사용 예시 (스택과 큐로 사용)
스택으로 사용 (
addFirst,removeFirst):1 2 3 4val stack: ArrayDeque<Int> = ArrayDeque() stack.addFirst(1) // push stack.addFirst(2) println(stack.removeFirst()) // pop, 출력: 2큐로 사용 (
addLast,removeFirst):1 2 3 4val queue: ArrayDeque<Int> = ArrayDeque() queue.addLast(1) // enqueue queue.addLast(2) println(queue.removeFirst()) // dequeue, 출력: 1
결론:
- Kotlin에서는
Deque를 직접 제공하지 않지만, Java의ArrayDeque또는LinkedList를 사용하여Deque와 같은 기능을 구현할 수 있습니다. ArrayDeque는 배열 기반으로, 빠른 삽입 및 삭제를 지원하는 반면,LinkedList는 노드 기반으로 동작합니다.- 이 두 클래스는
Deque인터페이스를 구현하고 있으며, 이를 통해 양방향 큐를 편리하게 사용할 수 있습니다.
ArrayDeque의 기능들
1. 삽입 메서드
addFirst(element: E): 큐의 앞쪽에 요소를 추가합니다.1 2 3 4val deque = ArrayDeque<Int>() deque.addFirst(1) deque.addFirst(2) println(deque) // 출력: [2, 1]addLast(element: E): 큐의 뒤쪽에 요소를 추가합니다.1 2deque.addLast(3) println(deque) // 출력: [2, 1, 3]offerFirst(element: E): 큐의 앞쪽에 요소를 추가하고, 성공하면true, 실패하면false를 반환합니다.offerLast(element: E): 큐의 뒤쪽에 요소를 추가하고, 성공하면true, 실패하면false를 반환합니다.
2. 삭제 메서드
removeFirst(): 큐의 앞쪽에서 요소를 제거하고 반환합니다. 만약 큐가 비어 있으면NoSuchElementException을 발생시킵니다.1 2println(deque.removeFirst()) // 출력: 2 println(deque) // 출력: [1, 3]removeLast(): 큐의 뒤쪽에서 요소를 제거하고 반환합니다. 큐가 비어 있으면NoSuchElementException을 발생시킵니다.1 2println(deque.removeLast()) // 출력: 3 println(deque) // 출력: [1]pollFirst(): 큐의 앞쪽에서 요소를 제거하고 반환합니다. 비어 있으면null을 반환합니다.pollLast(): 큐의 뒤쪽에서 요소를 제거하고 반환합니다. 비어 있으면null을 반환합니다.
3. 조회 메서드
getFirst(): 큐의 앞쪽 요소를 반환하지만, 제거하지 않습니다. 큐가 비어 있으면NoSuchElementException을 발생시킵니다.1println(deque.getFirst()) // 출력: 1getLast(): 큐의 뒤쪽 요소를 반환하지만, 제거하지 않습니다. 큐가 비어 있으면NoSuchElementException을 발생시킵니다.1 2deque.addLast(5) println(deque.getLast()) // 출력: 5peekFirst(): 큐의 앞쪽 요소를 반환하지만, 제거하지 않습니다. 비어 있으면null을 반환합니다.peekLast(): 큐의 뒤쪽 요소를 반환하지만, 제거하지 않습니다. 비어 있으면null을 반환합니다.
4. 기타 메서드
size:Deque의 크기를 반환합니다.1println(deque.size) // 출력: 2isEmpty():Deque가 비어 있으면true, 비어 있지 않으면false를 반환합니다.1println(deque.isEmpty()) // 출력: falseclear():Deque의 모든 요소를 제거합니다.1 2deque.clear() println(deque) // 출력: []
5. 스택 기능으로 사용
push(element: E): 스택의 맨 위에 요소를 추가합니다. (addFirst와 동일한 동작)1 2 3 4val stack = ArrayDeque<Int>() stack.push(10) stack.push(20) println(stack) // 출력: [20, 10]pop(): 스택의 맨 위에 있는 요소를 제거하고 반환합니다. (removeFirst와 동일한 동작)1 2println(stack.pop()) // 출력: 20 println(stack) // 출력: [10]
6. 큐 기능으로 사용
offer(element: E): 큐의 뒤쪽에 요소를 추가합니다. (offerLast와 동일)1 2 3 4val queue = ArrayDeque<Int>() queue.offer(100) queue.offer(200) println(queue) // 출력: [100, 200]poll(): 큐의 앞쪽에서 요소를 제거하고 반환합니다. (pollFirst와 동일)1 2println(queue.poll()) // 출력: 100 println(queue) // 출력: [200]
ArrayDeque의 특징:
스택과 큐 모두 지원:
ArrayDeque는 양방향 큐로서 스택이나 큐로 유연하게 사용할 수 있습니다.Null 허용 안 함:
ArrayDeque는null요소를 허용하지 않습니다.크기 조정 가능: 배열 기반이지만 동적으로 크기가 조정됩니다.
성능:
ArrayDeque는 가변 배열로 구현되어 있으며, 삽입과 삭제가 매우 빠릅니다.LinkedList에 비해 메모리 사용량이 적고 성능이 뛰어납니다.
Python의 defaultdict을 Kotlin으로 구현하는 법
defaultdict를 Kotlin에서 구현하는 방법
getOrPut 함수는 주어진 키가 없으면 기본 값을 생성하고, 해당 값을 맵에 넣어주는 역할을 한다.
defaultdict(lambda: list)와 동일한 기능을 구현하려면 MutableMap을 사용해보자.
| |
코드 설명
mutableMapOf(): 변경 가능한 맵을 생성한다.getOrPut(): 주어진 키에 해당하는 값을 반환하고, 키가 없으면 기본 값을 넣은 후 반환한다.- 첫 번째 매개변수는 키(
key1,key2)다. - 두 번째 매개변수는 값이 없을 때 제공할 기본 값으로,
mutableListOf()를 사용하여 빈 리스트를 생성한다.
- 첫 번째 매개변수는 키(
더 간단한 함수로 감싸기
defaultdict처럼 쓰기 위해 특정 함수로 감싸는 것도 가능하다.
| |
코드 설명
withDefault: 기본 값을 설정할 수 있는Map의 확장 함수다. 지정된 기본 값이 없을 때 호출된다.defaultMap함수: Python의defaultdict처럼 기본값을 설정할 수 있는MutableMap을 반환한다.
참고
map[key]: 키가 없으면null을 반환한다.map.getValue(key): 키가 없으면 지정된 기본 값을 반환한다. (그러나 맵에 추가되지는 않는다.)withDefault: 키가 없을 때 기본 값을 제공하지만, 맵에는 값을 추가하지 않는다.map[key]로 접근하면null이 반환된다.
getOrPut: 키가 없으면 기본 값을 추가하고, 값을 반환한다.