[Kotlin] Kotlin FP (2) - Collections 소개 (+ lambda)

yuseon Lim·2021년 4월 20일
0

Kotlin

목록 보기
10/11
post-thumbnail
post-custom-banner

Collection

함수형 프로그래밍에서 Collection을 사용 할 때, lambda가 편리하게 사용됨
이 페이지에서 소개할 collection들~

  • filter : 특정 조건을 만족하는 원소만 포함하는 Collection 생성, 리턴
  • map : 모든 원소에 대해 특정 연산을 수행한 결과를 모아서 Collection을 생성, 리턴
  • groupBy : 주어진 조건에 따라 Collection을 그룹으로 나눈 후 map을 생성, 리턴
  • all : 모든 원소가 특정 조건을 만족하면 true, 그렇지 않으면 false
  • any : 한 원소라도 특정 조건을 만족하면 true, 그렇지 않으면 false
  • count : 특정 조건을 만족하는 원소의 갯수를 리턴
  • find : 특정 조건을 만족하는 가장 처음 원소를 리턴
  • flatMap : 중첩된 Collection을 하나의 리스트로 생성, 리턴
  • asSequence

출처: 허준영교수님 github

😊 예제 실습은 안드로이드 스튜디오의 스크래치(.kts)에서 했습니다!
그래서 예제 코드는 println() 이라던가 fun main() 등이 빠져있습니다.

filter

리스트를 리터레이션하면서 리턴이 true인 값만 필터링.
리스트와 같이 쓰며 기본 구조는 이렇다.

val caffeMenuList = listOf("americano", "caffelatte"
        , "cappuccino", "earlgreytea", "greentea")

cafeMenuList.filter {
    // 조건
    // 리턴이 true인 것들만 필터링.
}

다양한 기능을 수행하는 Filter들.

val caffeMenuList = listOf("americano", "caffelatte"
        , "cappuccino", "earlgreytea", "greentea")

// filter는 조건이 true인 것을 필터링
caffeMenuList.filter {
    it.startsWith("a") // [americano]
}

// filterNot 조건이 true가 아닌것을 필터링
caffeMenuList.filterNot {
    it.startsWith("a") // [caffelatte, cappuccino, earlgreytea, greentea]
}

// filterIndexed 인덱스와 같이 사용하고 싶을때 사용
caffeMenuList.filterIndexed { index, s ->
    index == 1 // [caffelatte]
}

👀 지금 자연스럽게 lambda와 함께 사용했는데, collectionlambda는 함께 사용하면 매우매우 편리하다!

lambda와 collection

collection에서 lambda가 사용되는 과정은 이렇다.
(허준영교수님 github 참고해서 작성하였습니다)

val num = listOf(1,2,3,4,5,6,7,8,9,10)

// 결과는 모두 [1, 2, 3, 4]
num.filter({ n: Int -> n < 5 })

// 람다가 함수 인자의 마지막으로 사용되면
// 함수의 괄호 밖으로 뺄 수 있다.
num.filter(){ n: Int -> n < 5 } // [1, 2, 3, 4]

// 람다가 함수의 유일한 인자이면, 함수의 괄호를 생략 할 수 있음.
num.filter{ n: Int -> n < 5 }

// 인자 타입 생략 가능한 경우
num.filter{ n -> n < 5 }

// 디폴트 매개변수 이름으로 it을 사용할 수 있음
num.filter { it < 5 }

map

모든 원소에 대해 특정 연산을 수행한 결과를 모아서 Collection을 생성, 리턴

val num = listOf(1,2,3,4,5,6,7,8,9,10)
num.map { it + 10 } // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
num.map { it * it } // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

groupBy

주어진 조건에 따라 Collection을 그룹으로 나눈 후 map을 생성, 리턴

data class Person (val name: String, val age: Int)
val person = listOf(Person("홍길동", 20),
        Person("김철수", 25), Person("박영희", 20))

person.groupBy { it.age }
// {20=[Person(name=홍길동, age=20), Person(name=박영희,
// age=20)], 25=[Person(name=김철수, age=25)]}

all, any, count, found

  • all : 모든 원소가 특정 조건을 만족하면 true, 그렇지 않으면 false
  • any : 한 원소라도 특정 조건을 만족하면 true, 그렇지 않으면 false
  • count : 특정 조건을 만족하는 원소의 갯수를 리턴
  • find : 특정 조건을 만족하는 가장 처음 원소를 리턴
val num = listOf(-1,-2,-3,-4,-5,6,7,8,9,10)
num.all{ it is Int } // true
num.all{ it > 0 } // false
num.count{ it > 0 } // 5
num.find{ it > 0 } // 6

flatMap

  • flatMap : 중첩된 Collection을 하나의 리스트로 생성, 리턴 (map() 과 비슷하지만 반환형이 iterable)
  • 람다로 map을 만들고 이를 다시 flat하게 만듦
  • 즉, map을 처리하고 난 다음의 결과가 list인 경우 이 list의 원소를 다시 펼쳐서 하나의 list로 만듦
val str = listOf("abc", "efg")
str.flatMap { it.toList() } // [a, b, c, e, f, g]

asSequence

  • collections에 대해 정의된 lambda를 인자로 받는 확장함수들(filter, map, find, groupBy)는 inline함수로 정의되어 바로 리스트를 생성해주었음
  • 하지만, collection 확장 함수의 경우 항상 새로운 collection이 생성되어 데이터가 클때는 문제가 될 수 있음.
  • 이때, Sequence를 사용해
    • 리스트 생성을 최대한 늦춤
    • 실제 리스트 생성 작업을 최대한 늦추기 때문에 lazy연산이라고도 부름
  • List생성을 늦춘것이 Sequence이기 때문에 Collection으로 바꾸기 위해서 toList() 를 사용.
val num = listOf(1,2,3,4,5,6,7,8,9,19)
println(num.filter{ it < 6 }) // [1, 2, 3, 4, 5]

println(num.asSequence().filter{ it < 6 })
// kotlin.sequences.FilteringSequence@2ff4acd0

println(num.asSequence().filter{ it < 6 }.toList())
// [1, 2, 3, 4, 5]

참고자료

profile
🔥https://devyuseon.github.io/ 로 이사중 입니다!!!!!🔥
post-custom-banner

0개의 댓글