[자바 개발자를 위한 코틀린 입문] 컬렉션을 함수형으로 다루기
by dev.hardy코틀린에서 컬렉션을 함수형으로 다루는 방법
인프런에서 최태현 지식 공유자
님의자바 개발자를 위한 코틀린 입문
을 수강하며 정리한 내용 입니다.
하단에 강의 링크 있습니다.
필터와 맵
예) 사과만 주세요 : filter
fun main() {
val fruits = listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000),
)
val apples = fruits.filter { fruit -> fruit.name == "사과"}
val applesIndex = fruits.filterIndexed{ idx, fruit -> // (1)
println(idx)
fruit.name == "사과"
}
}
(1) filter에서 인덱스가 필요하다면 → filterIndexed
사용하면 된다.
예) 사과의 가격들을 알기: map
fun main() {
val fruits = listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000),
)
val applePrices = fruits
.filter { fruit -> fruit.name == "사과" }
.map { fruit -> fruit.currentPrice }
}
→ 인덱스가 필요하다면: mapIndexed
사용하면 된다.
예) Mapping 결과가 null이 아닌 것만 가져오고 싶다면?
val bananaNotNull = fruits.filter { fruit -> fruit.name == "바나나" }
.mapNotNull { fruit -> fruit.nullOrValue() }
→ filter에 null 이 아닌것만 넘어오는 것을 추가하지 않고 mapNotNull
을 사용하면 null이 아닌것만 mapping 할 수 있다.
다양한 컬렉션 처리 기능
all
: 조건을 모두 만족하면 true 그렇지 않으면 false
예) 모든 과일이 바나나 인가요?
fun main() {
val fruits = listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000),
)
val targetName = "바나나"
val isAllBanana = fruits.all { fruit -> fruit.name == targetName }
println(isAllBanana) // false
}
→ all과 반대로 none
도 있다. (조건을 모두 불만족하면 true 그렇지 않으면 false)
→ any
: 조건을 하나라도 만족하면 true, 그렇지 않으면 false
예) count: 개수를 세는 것 / 사과의 개수는 총 몇개인지?
fun main() {
val fruits = listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000),
)
val targetName = "사과"
val appleCount = fruits.count { fruit -> fruit.name == targetName }
println(appleCount) // 2
}
그 외의
sortedBy
: (오름차순) 정렬 /sortedByDescending
: (내림차순) 정렬distinctBy
: 변형된 값을 기준으로 중복 제거
예) 첫번째 과일만 주세요
first
: 첫번째 값을 가져온다. (무조건 null이 아니어야 한다.)firstOrNull
: 첫 번째 값 또는 null일 경우 null을 가져온다.
fun main() {
val fruits = listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000),
)
val fruit = fruits.first()
println("id = ${fruit.id}") // id = 1
}
반대로 last
, lastOrNull
도 있다.
List를 Map으로
예) 과일이름 → List<과일> 형식의 (key, value) 형태인 Map을 만들어보자
fun main() {
val fruits = listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000),
)
val fruitMap : Map<String, List<Fruit>> = fruits.groupBy { fruit -> fruit.name }
println(fruitMap["사과"])
}
/**
[Fruit(id=1, name=사과, factoryPrice=3000, currentPrice=2000), Fruit(id=2, name=사과, factoryPrice=4000, currentPrice=3000)]
*/
예) id가 key , 과일이 value 인 Map
fruits.associateBy { fruit -> fruit.id }
→ groupBy와 달리 associateBy
는 value에 단일 객체가 들어간다.
🤠 key와 value를 동시에 처리 가능하다.
예) (과일이름 , List<출고가>) 인 MAP
fruits.groupBy({fruit -> fruit.name}, {fruit -> fruit.factoryPrice})
예) id → 출고가 Map
fruits.associateBy({fruit -> fruit.id}, {fruit -> fruit.factoryPrice})
중첩된 컬렉션 처리
예) 출고가와 현재가가 동일한 과일들을 골라주세요
fun main() {
val fruits = listOf(
listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000)
),
listOf(
Fruit(5,"사과", 3000, 2000),
Fruit(6,"사과", 4000, 3000),
Fruit(7,"바나나", 6000, 5000),
Fruit(8,"수박", 13000, 12000)
)
)
fruits.flatMap {list -> // (1)
list.filter { fruit -> fruit.factoryPrice == fruit.currentPrice }
}
}
(1) flatMap
을 사용하면 List List → 단일 리스트로 바뀌게 된다.
람다안의 람다가 있기 때문에 다음과 같이 리팩토링 가능하다.
data class Fruit(
val id: Long,
val name: String,
val factoryPrice: Long,
val currentPrice: Long
){
val isSamePrice : Boolean // 추가
get() = factoryPrice == currentPrice
}
fun main() {
val fruits = listOf(
listOf(
Fruit(1,"사과", 3000, 2000),
Fruit(2,"사과", 4000, 3000),
Fruit(3,"바나나", 6000, 5000),
Fruit(4,"수박", 13000, 12000)
),
listOf(
Fruit(5,"사과", 3000, 2000),
Fruit(6,"사과", 4000, 3000),
Fruit(7,"바나나", 6000, 5000),
Fruit(8,"수박", 13000, 12000)
)
)
fruits.flatMap {list -> list.samePriceFilter} // 확장함수를 호출하여 하나의 람다만 사용하는 것 처럼 보이게
}
val List<Fruit>.samePriceFilter: List<Fruit> // 확장함수를 만든다.
get() = this.filter(Fruit::isSamePrice)
- 중첩된 컬렉션은 풀려면 →
flatten()
사용
Reference:
자바 개발자를 위한 코틀린 입문
블로그의 정보
개발자 하디 : 기록저장소
dev.hardy