
위를 보면 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의 경우 ListIterator라는 특수한 Iterator가 있다. 이는 hasPrevious, previous, nextIndex, previousIndex 를 추가적으로 가진다.
mutableIterator는 MutableCollection가 가진 Iterator이다.
remove라는 매서드를 가지고 있으며. remove를 하면 iterator가 현재 가르키고 있는 요소가 사라진다.
Collection에서도 사라진다.
조금 더 확대해서 보면

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

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

lastRet이 가르키고 있는 요소가 사라진다.
요소를 가지고 있지 않는 Collection의 한 종류이다.
Iterable과 같은데 조금 다르다
Iterable는
Sequence는
Sequence는 중간결과를 저장하지 않기 때문에 메모리가 절약되고, 필요한 요소만 계산(LAZY방식)하므로 더 빠르다
따라서
Iterable은 작은 컬렉션, 간단한 계산에
Sequence는 큰 데이터 혹은 계산이 복잡한 경우에
sequenceOf를 이용하여 만들거나 List를 asSequence를 이용해 만든다.
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을 반환시 시퀀스를 종료한다.
한번에 하나의 요소 혹은 하나의 청크(조각) 으로 만들 수 있는 sequence의 기능이다.
yield와 yieldAll 두개의 매서드로 나뉘며
yield()yeildAllval sequence = sequence<Int> {
yield(12)
yieldAll(generateSequence(1) { it + 1 })
}
println(sequence.take(10).toList())
이렇게 사용한다.
Sequences는 크게 2가지로 나뉘는데
1. Stateless
2. Stateful
이다.
상태가 없을때는, 각각의 요소들이 독립적으로 실행된다. map, filter와 같은 녀석들이 그 예다.
take, drop 같은 연산은 요소를 처리하는데 상수량? 의 상태가 필요하다고 한다.
요소의 수와 관련된 많은 상태를 필요로 하는데.
당연히 내부 상태를 관리해야 하며 distinct, sorted 같은 연산이 그 예입니다.
중간 연산, 종단 연산 으로 분류됩니다.
Intermediate연산은 다른 시퀀스를 반환하는데 LAZY하게 생성되고, 이 연산은 데이터를 가지고 작업을 수행하며 최종 결과를 생성하지는 않습니다
Terminal 연산은 결과를 생성하고 시퀀스를 종료하는데
toList, sum 같은 연산이 여기에 속하고 반드시 종단 연산을 호출해야 그 결과를 얻을 수 있습니다.
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
