filter, map
filter : 컬렉션을 이터레이션하며 주어진 람다에 각 원소를 넘겨서 람다가 true 를 반환하는 원소만으로 이뤄진 새로운 컬렉션을 반환하는 함수
- 입력 컬렉션의 원소 중에서 주어진 술어 predicate 를 만족하는 원소들의 컬렉션을 반환
- 컬렉션에서 원치 않는 요소를 제거할 때 사용
술어 predicate
참, 거짓을 반환하는 함수
EX. 나이가 30 초과인 Person 객체들의 컬렉션을 반환
val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.filter { it.age > 30 })
[Person(name=Bob, age=31)]
map : 주어진 람다를 컬렉션의 각 원소에 적용한 결과를 모아 새 컬렉션을 반환한다.
- 컬렉션 원소들을 변형시키고 싶을 때 사용
EX. Person 객체 컬렉션의 이름만을 추출해 이름 컬렉션을 반환
val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.map { it.name })
[Alice, Bob]
// 멤버 참조를 이용할 수 도 있다.
println(people.map(Person::age))
filter와 map 를 연쇄시켜 사용할 수 있다.
EX. 나이가 30초과인 사람들의 나이만을 추출한 컬렉션을 반환
val people = listOf(Person("Alice", 29), Person("Bob", 31), Person("Minux", 42))
println(people.filter { it.age > 30 }.map(Person::age))
[31, 42]
맵 컬렉션에서 filter와 map 함수를 이용할 수 있다.
- filterKeys, mapKeys : 키를 걸러 내거나 변환
- filterValues, mapValues 는 값을 걸러 내거나 변환
val numbers = mapOf(0 to "zero", 1 to "one")
println(numbers.mapValues { it.value.uppercase() })
{0=ZERO, 1=ONE}
EX. 컬렉션 함수형 API 를 중첩으로 사용할 때 주의
// 원소의 개수에 따라 maxBy 가 계속 반복된다는 단점이 있다.
people.filter { it.age == people.maxBy(Person::age)!!.age }
// maxAge 를 한 번만 계산해 filter 에 이용하는 것이 효율적
val maxAge = people.maxBy(Person::age)!!.age
people.filter { it.age == maxAge }
all, any, count, find
- all : 컬렉션의 모든 원소가 어떤 조건을 만족하는지 판단하여 true, false 를 반환
- any : 컬렉션의 어떤 조건을 만족하는 원소가 있는 판단하여 true, false 를 반환
- count : 조건을 만족하는 원소의 개수를 반환
- find : 조건을 만족하는 첫 번째 원소를 반환, 없는 경우 null 을 반환 ⇒ firstOrNull 과 같다.
val people = listOf(Person("Alice", 29), Person("Bob", 31), Person("Minux", 20))
val canBeInClub27 = { p: Person -> p.age <= 27 } // 27살 이하인지 판단하는 술어 함수
println(people.all(canBeInClub27))
false
println(people.any(canBeInClub27))
true
println(people.count(canBeInClub27))
1
println(people.find(canBeInClub27))
Person(name=Minux, age=20)
- all, any는 같은 결과를 도출하더라도 어떻게 사용하느냐에 따라 가독성이 달라진다.
val list = listOf(1, 2, 3)
println(!list.all { it == 3}) // ! 연산자가 가독성이 없으므로
println(list.any { it != 3 }) // any 함수와 부정 술어를 사용
groupBy
컬렉션의 모든 원소를 어떤 특성에 따라 여러 그룹으로 나누어 맵을 반환하는 함수이며, 결과 타입은 Map<K, V> 이다.
- 생성된 맵은 mapKeys 나 mapValues 등을 사용해 변경하여 이용
EX. 나이가 같은 Person 객체들을 맵 <Int, List<Person>> 타입으로 그룹화
val people = listOf(Person("Alice", 29), Person("Bob", 31), Person("Minux", 29))
println(people.groupBy { it.age })
{29=[Person(name=Alice, age=29), Person(name=Minux, age=29)], 31=[Person(name=Bob, age=31)]}
EX.문자열의 첫 번째 캐릭터를 기준으로 맵 타입으로 그룹화
val list = listOf("a", "ab", "b")
println(list.groupBy(String::first))
{a=[a, ab], b=[b]}
flatMap, flatten
flatMap : 인자로 주어진 람다를 컬렉션의 모든 객체에 적용하고, 람다를 적용한 결과 얻어지는 여러 리스트를 한 리스트로 한데 모으는 함수
- 리스트의 리스트가 있는데 모든 중첩된 리스트의 원소를 한 리스트로 모아야 할 때 사용
EX. 두 리스트를 하나의 리스트로 합쳐서 반환
val strings = listOf("abc", "def")
println(strings.flatMap { it.toList() }) // ["a", "b", "c"] , ["d", "e", "f"] 두 리스트가 생성
[a, b, c, d, e, f] // 하나의 리스트로 합쳐진다.
EX. Book 의 저자 컬렉션을 한 리스트로 모으고, 집합으로 변환
data class Book (val title: String, val authors: List<String>)
val books = listOf(
Book("Thursday Next", listOf("Jasper Forde")),
Book("Mort", listOf("Terry Pratchett")),
Book("Good Omens", listOf("Terry Pratchett", "Neil Gaiman"))
)
println(books.flatMap { it.authors }.toSet())
[Jasper Forde, Terry Pratchett, Neil Gaiman]
flatten : 변환할 내용 없이 리스트의 리스트를 평평하게 펼치는 함수
val listOfLists = listOf(listOf(1, 2, 3), listOf(4, 5, 6), listOf(7, 8, 9))
println(listOfLists.flatten())
[1, 2, 3, 4, 5, 6, 7, 8, 9]
728x90
'Kotlin' 카테고리의 다른 글
Coroutine (0) | 2024.02.13 |
---|---|
변수와 상수 (0) | 2023.11.02 |
수신 객체 지정 람다, with 와 apply (0) | 2023.09.08 |
자바 함수형 인터페이스 활용 (0) | 2023.09.07 |
지연 계산 Lazy 컬렉션 연산 (0) | 2023.09.06 |