Languages

kotlin의 lazy evaluation (sequence, map, filter)

!쪼렙조햄 2020. 4. 26. 21:36
반응형

5.3 지연 계산(lazy) 컬렉션 연산

  • map, filter 컬렉션 함수
    • 결과 컬렉션을 즉시 생성한다
// 그냥 collection 함수 연쇄적으로 사용
people.map(Person::name).filter{it.startsWith("A")}

// sequence 사용
people.asSequence()
    .map(Person::name)
    .filter{it.startsWith("A")}
    .toList()
  • filter, map 모두 collection을 반환한다
    • collection의 크기가 커지면 위 연쇄 호출은 리스트 2개를 만들게 되어 효율이 떨어진다
    • 각 연산이 컬렉션을 직접 사용하는 대신 시퀀스 사용하도록 변경해야 함
  • sequence 사용하는 경우
    • collection을 sequence로 변경 한 후, 연산 진행 이후 다시 collection으로 변경
    • sequence 안에는 iterator라는 단 하나의 메소드가 있다?
      • 이 메소드를 통해 시퀀스로부터 원소 값을 얻을 수 있다
    • lazy evaluation 을 통해 효율적으로 계산
    • asSequence()
      • 모든 collection을 sequence로 변경 가능하다
    • toList()
      • sequence를 다시 collection으로 변경
    • sequence vs collection
      • sequence
        • 원소를 인덱스를 사용해서 접근하는 등의 메소드 아쉽다
        • 큰 collection에 연산 연쇄시킬때는 sequence 사용하는 것이 좋다

🧤 시퀀스 연산 실행 : 중간 연산과 최종 연산

  • kotlin : sequence, java : stream
  • 중간연산 (map, filter..) 은 항상 지연연산
  • 최종연산이 호출되기 전까지는 아무것도 계산되지 않는다
println(listOf(1,2,3,4).asSequence()
    .map{it*it}.find{it>3})
  • collection으로 직접 연산 하는 경우
    • 각 map, filter등의 연산으로 collection을 각각 다 만든다
      • 1,4,9,16 가진 collection을 만든다음 찾는다
  • sequence 연산 하는 경우
    • 각 원소별로 연산을 적용하기 때문에 일정 범위 밖의 원소에 대해서는 변환이 이루어지지 않을 수도 있다
      • find 사용하는 경우
      • 1해보고, 2로 4 만든다음 찾으면 끝
    • 여기서 find는 최종연산인가??
  • 수행하는 연산의 순서
    • map 다음에 filter을 하지 않고 filter 먼저 하면 계산의 결과는 같아도 수행해야 하는 연산의 양이 작아서 효율성이 높다

👗 시퀀스 만들기

  • Sequence 만드는 법
    • collection을 asSequence() 사용하여 sequence로 변환
    • listOf, setOf 처럼 sequenceOf 를 사용하는 방법도 있음
    • generateSequence() 함수 사용
      • 시작 element와, iteration 연산값을 이용하여 sequence 생성
val naturalNumbers = generateSequence(0){it+1}
val numbersTo100 = naturalNumbers.takeWhile{it<=100}
println(numbersTo100.sum())
  • naturalNumbers, numbersTo100 둘다 Sequence
  • takeWhile
    • 조건 만족 전까지 return
    • take, takeWhile, takeIf, takeLast...
  • 최종연산 : sum
fun File.isInsideHiddenDirectory() = 
    generateSequence(this){it.parentFile}.any{it.isHidden}
val file = File("/Users/user/a.txt")
println(file.isInsideHiddenDirectory())
  • generateSequence 함수로 Sequence 생성
    • this 넣고, it.parentFile로 this의 부모 폴더를 File 형식으로 return
  • +
    • generateSequence 함수로 유한한 Sequence 만들기
      • 마지막 element 뒤에 null을 리턴하는 함수로
      • generateSequence(1){ if (it < 10) it + 1 else null }

Reference

반응형