5.1.2 람다와 컬렉션
1. 라이브러리 함수를 사용하여 프로퍼티를 비교해 값이 가장 큰 원소 찾기
// 루프 사용
class Person(val name: String, val age: Int)
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
findTheOldest(people)
}
fun findTheOldest(people: List<Person>) {
var maxAge = 0
var theOldest: Person? = null
for (person in people) {
if (person.age > maxAge) {
maxAge = person.age
theOldest = person
}
}
println(theOldest?.age)
}
2. 람다를 사용해 컬렉션 검색
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.maxBy{it.age}.age)
}
3. 멤버 참조를 이용해 컬렉션 검색
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
println(people.maxBy(Person::age).age)
}
5.1.3 람다식의 문법
1. 람다 식을 maxBy 함수에 넘김
people.maxBy({p: Person -> p.age})
-> 람다를 괄호 밖으로 빼낼 수 있음
people.maxBy() {p: Person -> p.age}
-> 괄호 뒤에 람다가 썼다면 호출 시 빈 괄호를 없애도 됨
people.maxBy{p: Person -> p.age}
2. joinToString에 람다 사용
// 이름 붙인 인자를 사용해 람다 넘기기
class Person(val name: String, val age: Int)
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
val names = people.joinToString(separator = " ", transform = { p: Person -> p.name })
println(names)
}
// 람다를 괄호 밖에 전달
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 29), Person("Bob", 31))
val names = people.joinToString(separator = " ") { p: Person -> p.name }
println(names)
}
3. 람다의 파라미터 타입을 생략해도 컴파일러가 추론
people.maxBy{p -> p.age}
4. 람다의 파라미터가 하나뿐이고, 그 타입을 컴파일러가 추론할 수 있는 경우 it 사용 가능
people.maxBy{it.age}
5.1.5 멤버 참조
1. 람다를 이용해 넘기려는 코드가 이미 함수로 선언된 경우, 함수를 직접 넘길 수 있음
- 이중 콜론(::) 사용
- run은 인자로 받은 람다를 실행
2. 멤버 참조는 최상위 선언된 함수나 프로퍼티 참조 가능
fun main(args: Array<String>) {
run(::salute) // 최상위 함수 참조
}
fun salute() = println("Salute")
3. 람다가 인자가 여럿인 다름 함수에게 작업을 위임하는 경우, 직접 위임 함수에 대한 참조를 제공 가능
data class Person(val name: String, val age: Int)
fun main(args: Array<String>) {
val action = { person: Person, message: String ->
sendEmail(person, message)
}
action(Person("Alice",31), "Hello!")
action(Person("Bob",20), "Bye!")
}
fun sendEmail(person: Person, message: String) {
println("${person.name}에게 전송할 메시지: $message")
}
4. 생성자 참조를 사용하면 클래스 생성 작업 연기/저장 가능
data class Person(val name: String, val age: Int)
fun main(args: Array<String>) {
val createPerson = ::Person
val p = createPerson("Alice",31)
println(p)
}
5.2.1 필수적인 함수: filter와 map
1. map: 주어진 람다를 컬렉션의 각 원소에 적용한 결과를 모아서 새 컬렉션을 생성
data class Person(val name: String, val age: Int)
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 31), Person("Bob", 21))
println(people.map { it.name })
}
data class Person(val name: String, val age: Int)
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 31), Person("Bob", 21))
println(people.filter { it.age > 30 }.map (Person::name))
}
2. filter와 map을 맵에 적용
fun main(args: Array<String>) {
val numbers = mapOf(0 to "zero", 1 to "one")
println(numbers.mapValues { it.value.uppercase() })
}
5.2.4 flatMap과 flatten: 중첩된 컬렉션 안의 원소 처리
1. flatMap: 인자로 주어진 람다를 컬렉션의 모든 객체에 적용하고,
람다를 적용한 결과 얻어지는 리스트들을 한 리스트로 모음
fun main(args: Array<String>) {
val strings = listOf("가나다","라마바")
println(strings.flatMap { it.toList() })
}
fun main(args: Array<String>) {
val ls = listOf("가나다", "라마바")
val map = ls.map{it.toList()}
println("map: $map")
val flatten = map.flatten()
println("flatten: $flatten")
}
-> flatMap은 map -> flatten 동작과 같음
5.3 지연 계산(lazy) 컬렉션 연산
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 31), Person("Bob", 21))
val person = people.map(Person::name).filter { it.startsWith("A") }
println(person)
}
-> filter와 map은 모두 리스트를 반환하므로 위 연쇄 호출은 리스트를 2개 만들게 됨 (비효율적)
1. 시퀀스를 사용하면 중간 임시 컬렉션을 사용하지 않고 컬렉션 연산을 연쇄할 수 있음
fun main(args: Array<String>) {
val people = listOf(Person("Alice", 31), Person("Bob", 21))
val person =people.asSequence()
.map(Person::name)
.filter { it.startsWith("A") }
.toList()
println(person)
}
5.5.1 with 함수
fun alphabet() :String {
val result = StringBuilder()
for (letter in 'A'..'Z'){
result.append(letter)
}
result.append("\nNow I Know the alphabet!")
return result.toString()
}
-> result에 대해 다른 여러 메서드를 호출하며 매번 result를 반복
1. with함수는 첫 번째 인자로 받은 객체를 두 번째 인자로 받은 람다의 수신 객체로 만듦
- 람다의 본문에서는 this와 점(.)을 사용하지 않고 프로퍼티나 메서드 이름만 사용해도 수신 객체의 멤버에 접근 가능
fun alphabet() :String {
val stringBuilder = StringBuilder()
return with(stringBuilder) {
for (letter in 'A'..'Z'){
this.append(letter) // this 생략 가능
}
append("\nNow I Know the alphabet!")
this.toString()
}
}
2. with와 식을 본문으로 하는 함수를 활용하여 불필요한 stringBuilder 변수 제거 가능
fun alphabet() = with(StringBuilder()) {
for (letter in 'A'..'Z'){
append(letter)
}
append("\nNow I Know the alphabet!")
toString()
}
5.5.2 apply 함수
1. with함수와 비슷하지만, apply는 항상 자신에게 전달된 객체를 반환함
2. 객체의 인스턴스를 만들면서 즉시 프로퍼티 중 일부를 초기화해야 하는 경우 유용함
fun alphabet() = StringBuilder().apply {
for (letter in 'A'..'Z'){
append(letter)
}
append("\nNow I Know the alphabet!")
}.toString()
3. 표준 라이브러리의 buildString 함수를 사용하면 StringBuilder 객체 생성과, toString 호출을 알아서 해줌
fun alphabet() = buildString {
for (letter in 'A'..'Z'){
append(letter)
}
append("\nNow I Know the alphabet!")
}
'Android > Kotlin' 카테고리의 다른 글
[코틀린 인 액션] 7장 정리: 연산자 오버로딩 (0) | 2022.12.05 |
---|---|
[코틀린 인 액션] 6장 정리: null 다루는 방법 (0) | 2022.11.30 |
[코틀린 인 액션] 4장 정리 (0) | 2022.11.29 |
[코틀린 인 액션] 3장 정리 (0) | 2022.11.28 |
[코틀린 인 액션] 2장 정리 (0) | 2022.11.24 |