컬렉션의 고차 함수들
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 4
val pq = PriorityQueue<Int>() pq.add(10) pq.add(5) pq.add(20)
offer(element: E): Boolean
:add()
와 동일하게 요소를 큐에 추가하지만 예외를 던지지 않는다. 성공 여부를Boolean
으로 반환한다.1
pq.offer(15)
poll(): E?
: 우선순위가 가장 높은(가장 작은) 요소를 제거하고 반환한다. 큐가 비어있으면null
을 반환한다.1
val minValue = pq.poll()
remove(element: E): Boolean
: 특정 요소를 큐에서 제거하고, 성공하면true
를 반환한다. 큐에 해당 요소가 없으면false
를 반환한다.1
val isRemoved = pq.remove(5)
2.2. 조회
peek(): E?
: 큐에서 우선순위가 가장 높은 요소를 제거하지 않고 반환한다. 큐가 비어 있으면null
을 반환한다.1
val topValue = pq.peek()
element(): E
:peek()
와 동일하게 가장 높은 우선순위의 요소를 반환하지만, 큐가 비어있으면 예외(NoSuchElementException
)를 던진다.1
val firstElement = pq.element()
2.3. 상태 확인
isEmpty(): Boolean
: 큐가 비어 있는지 여부를 반환한다.size(): Int
2.4. 기타 함수
clear()
: 큐의 모든 요소를 제거한다.contains(element: E): Boolean
: 특정 요소가 큐에 포함되어 있는지 확인하고true
나false
를 반환한다toArray(): Array<Any?>
: 큐의 모든 요소를 배열로 반환한다.1
val 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 4
val stack: ArrayDeque<Int> = ArrayDeque() stack.addFirst(1) // push stack.addFirst(2) println(stack.removeFirst()) // pop, 출력: 2
큐로 사용 (
addLast
,removeFirst
):1 2 3 4
val 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 4
val deque = ArrayDeque<Int>() deque.addFirst(1) deque.addFirst(2) println(deque) // 출력: [2, 1]
addLast(element: E)
: 큐의 뒤쪽에 요소를 추가합니다.1 2
deque.addLast(3) println(deque) // 출력: [2, 1, 3]
offerFirst(element: E)
: 큐의 앞쪽에 요소를 추가하고, 성공하면true
, 실패하면false
를 반환합니다.offerLast(element: E)
: 큐의 뒤쪽에 요소를 추가하고, 성공하면true
, 실패하면false
를 반환합니다.
2. 삭제 메서드
removeFirst()
: 큐의 앞쪽에서 요소를 제거하고 반환합니다. 만약 큐가 비어 있으면NoSuchElementException
을 발생시킵니다.1 2
println(deque.removeFirst()) // 출력: 2 println(deque) // 출력: [1, 3]
removeLast()
: 큐의 뒤쪽에서 요소를 제거하고 반환합니다. 큐가 비어 있으면NoSuchElementException
을 발생시킵니다.1 2
println(deque.removeLast()) // 출력: 3 println(deque) // 출력: [1]
pollFirst()
: 큐의 앞쪽에서 요소를 제거하고 반환합니다. 비어 있으면null
을 반환합니다.pollLast()
: 큐의 뒤쪽에서 요소를 제거하고 반환합니다. 비어 있으면null
을 반환합니다.
3. 조회 메서드
getFirst()
: 큐의 앞쪽 요소를 반환하지만, 제거하지 않습니다. 큐가 비어 있으면NoSuchElementException
을 발생시킵니다.1
println(deque.getFirst()) // 출력: 1
getLast()
: 큐의 뒤쪽 요소를 반환하지만, 제거하지 않습니다. 큐가 비어 있으면NoSuchElementException
을 발생시킵니다.1 2
deque.addLast(5) println(deque.getLast()) // 출력: 5
peekFirst()
: 큐의 앞쪽 요소를 반환하지만, 제거하지 않습니다. 비어 있으면null
을 반환합니다.peekLast()
: 큐의 뒤쪽 요소를 반환하지만, 제거하지 않습니다. 비어 있으면null
을 반환합니다.
4. 기타 메서드
size
:Deque
의 크기를 반환합니다.1
println(deque.size) // 출력: 2
isEmpty()
:Deque
가 비어 있으면true
, 비어 있지 않으면false
를 반환합니다.1
println(deque.isEmpty()) // 출력: false
clear()
:Deque
의 모든 요소를 제거합니다.1 2
deque.clear() println(deque) // 출력: []
5. 스택 기능으로 사용
push(element: E)
: 스택의 맨 위에 요소를 추가합니다. (addFirst
와 동일한 동작)1 2 3 4
val stack = ArrayDeque<Int>() stack.push(10) stack.push(20) println(stack) // 출력: [20, 10]
pop()
: 스택의 맨 위에 있는 요소를 제거하고 반환합니다. (removeFirst
와 동일한 동작)1 2
println(stack.pop()) // 출력: 20 println(stack) // 출력: [10]
6. 큐 기능으로 사용
offer(element: E)
: 큐의 뒤쪽에 요소를 추가합니다. (offerLast
와 동일)1 2 3 4
val queue = ArrayDeque<Int>() queue.offer(100) queue.offer(200) println(queue) // 출력: [100, 200]
poll()
: 큐의 앞쪽에서 요소를 제거하고 반환합니다. (pollFirst
와 동일)1 2
println(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
: 키가 없으면 기본 값을 추가하고, 값을 반환한다.