Kotlin 기초 5

Tadap·2023년 10월 15일

Kotlin

목록 보기
5/6
post-thumbnail

Iterator

위를 보면 list, set은 Iterator를 가지고 있다.
iterator() 매서드를 통해 iterator를 가져오며
여러 매서드를 통해 확인 가능하다.

for문 in 뒤에 Collection을 넣으면 자동으로 iterator가 호출되어 반복된다.

val numbers = listOf("one", "two", "three", "four")
for (item in numbers) {
    println(item)
}

forEach도 동일하다

val numbers = listOf("one", "two", "three", "four")
numbers.forEach {
    println(it)
}

List Iterator

List의 경우 ListIterator라는 특수한 Iterator가 있다. 이는 hasPrevious, previous, nextIndex, previousIndex 를 추가적으로 가진다.

Mutable Iterator

mutableIterator는 MutableCollection가 가진 Iterator이다.
remove라는 매서드를 가지고 있으며. remove를 하면 iterator가 현재 가르키고 있는 요소가 사라진다.
Collection에서도 사라진다.

조금 더 확대해서 보면

Iterator는 위와 같이 cursor를 가지고 있는다.
여기서 next를 호출하면

위처럼 cursor가 움직이는 형태이다.
그리고 remove를 하면

lastRet이 가르키고 있는 요소가 사라진다.

Sequence

요소를 가지고 있지 않는 Collection의 한 종류이다.
Iterable과 같은데 조금 다르다

Iterable

  1. 컬렉션과 관련이 있으며
  2. 모든 요소가 이미 생성된 상태이다.
  3. 각 단계는 즉시 실행되며 중간 컬렉션을 반환하고
  4. 모든 단계가 처리된 후 최종 결과를 생성한다

Sequence

  1. LAZY 방식으로 처리를 해 나중에 생성된다.
  2. 다음 단계 이전에 현재 요소에 대한 처리부터 하며
  3. 전체 처리에 대한 요청이 들어올 때만 최종 결과를 계산하며 중간 결과를 저장하지 않는다.

Sequence는 중간결과를 저장하지 않기 때문에 메모리가 절약되고, 필요한 요소만 계산(LAZY방식)하므로 더 빠르다

따라서
Iterable은 작은 컬렉션, 간단한 계산에
Sequence는 큰 데이터 혹은 계산이 복잡한 경우에

생성법

1. SequenceOf

sequenceOf를 이용하여 만들거나 ListasSequence를 이용해 만든다.

2. generateSequence

  • 무한 시퀀스
val oddNumbers = generateSequence(1) { it + 2 } // `it` is the previous element
println(oddNumbers.take(5).toList())
//println(oddNumbers.count())     // error: the sequence is infinite
  • 유한 시퀀스
val oddNumbersLessThan10 = generateSequence(1) {
	if (it < 8) it + 2 else null
}
println(oddNumbersLessThan10.count())

function으로 위처럼 생성 가능하다.
null을 반환시 시퀀스를 종료한다.

3. Chunks

한번에 하나의 요소 혹은 하나의 청크(조각) 으로 만들 수 있는 sequence의 기능이다.
yieldyieldAll 두개의 매서드로 나뉘며

  1. yield()
    하나의 요소만 반환
  2. yeildAll
    Iterable, Iterator, Sequence 에서 요소를 가져와서 반환하는데 이 때 여러가지 요소를 한번에 반환한다.
val sequence = sequence<Int> {
        yield(12)
        yieldAll(generateSequence(1) { it + 1 })
    }
    
    println(sequence.take(10).toList())

이렇게 사용한다.

함수 분류

상태에 따른 분류

Sequences는 크게 2가지로 나뉘는데
1. Stateless
2. Stateful
이다.

Stateless

상태가 없을때는, 각각의 요소들이 독립적으로 실행된다. map, filter와 같은 녀석들이 그 예다.

take, drop 같은 연산은 요소를 처리하는데 상수량? 의 상태가 필요하다고 한다.

Stateful

요소의 수와 관련된 많은 상태를 필요로 하는데.
당연히 내부 상태를 관리해야 하며 distinct, sorted 같은 연산이 그 예입니다.

연산에 따른 분류

중간 연산, 종단 연산 으로 분류됩니다.

중간 연산

Intermediate연산은 다른 시퀀스를 반환하는데 LAZY하게 생성되고, 이 연산은 데이터를 가지고 작업을 수행하며 최종 결과를 생성하지는 않습니다

  • map: 요소를 변환해서 새로운 시퀀스 생성
  • filter: 조건에 맞는 요소만으로 구성된 시퀀스 생성
  • distinct: 중복 제거한 시퀀스 생성
  • sorted: 정렬한 시퀀스 생성
  • zip: 다른 시퀀스와 짝지어 새로운 시퀀스 생성
  • take: 처음 n개의 요소로 구성된 새로운 시퀀스 생성
  • drop: 처음 n개를 제외한 새로운 시퀀스 생성
  • flatMap: 각 요소를 여러요소로 확장하여 새로운 시퀀스 생성

종단 연산

Terminal 연산은 결과를 생성하고 시퀀스를 종료하는데
toList, sum 같은 연산이 여기에 속하고 반드시 종단 연산을 호출해야 그 결과를 얻을 수 있습니다.

  • toList: 리스트로
  • toSet: set으로
  • toMap: map으로
  • count: 요소 개수 반환
  • any: 조건을 만족하는 요소가 하나 이상 있는지?(or)
  • all: 모든 요소가 조건을 만족하는지?(and)
  • reduce: 요소를 줄여가면 값을 계산
  • fold: 초기값과 함꼐 줄여가면 계산
  • sumBy: 선택자 함수를 사용하여 계산

Iterator와 비슷하다는걸 인지하면
체이닝해가면서 계산을 한다는 것을 알 수있다.
Iterator와의 차이점은 메모리를 덜먹고 LAZY 방식이기 때문에 필요한 요소만 계산해서 조금 더 빠르다는 차이점이 있다.

아래 예시 두개를 보면

//Iterator
val words = "The quick brown fox jumps over the lazy dog".split(" ")
val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
    .map { println("length: ${it.length}"); it.length }
    .take(4)

println("Lengths of first 4 words longer than 3 chars:")
println(lengthsList)

//Sequence
val words = "The quick brown fox jumps over the lazy dog".split(" ")
//convert the List to a Sequence
val wordsSequence = words.asSequence()

val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
    .map { println("length: ${it.length}"); it.length }
    .take(4)

println("Lengths of first 4 words longer than 3 chars")
// terminal operation: obtaining the result as a List
println(lengthsSequence.toList())

위를 Debug모드로 두고 실행하면 차이점이 명확해진다.
Iterator를 filter, map, take를 사용할 때 마다 메모리에 적재가 되지만.
Sequence는 아무일도 안일어난다.
이후 print하는 순간 한번에 실행하며 선택한 요소들만 출력하기 때문에 다르다.
아래는 각각에 대한 설명 사진이다.

Iterator

Sequence

다음 공부할 doc위치

0개의 댓글