TIL

Lec 18. 코틀린에서 컬렉션을 함수형으로 다루는 방법

1. 필터와 맵

// 예제 데이터
data class Fruit(
  val id: Long,
  val name: String,
  val factoryPrice: Long,
  val currentPrice: Long
)

filter

// 사과만 필터링
val apples = fruits.filter { it.name == "사과" }

// 필터에서 인덱스가 필요한 경우
val apples = fruits.filterIndexed { idx, fruit -> 
  println(idx)
  fruit.name == "사과"
}

map

// 사과 가격을 알고 싶다
val applePrices = fruits
            .filter { it.name == "사과" }
            .map { it.currentPrice }
            
// 맵에서 인덱스가 필요한 경우
val applePrices = fruits
            .filter { it.name == "사과" }
            .mapIndexed { idx, fruit -> 
              println(idx)
              fruit.currentPrice
            }    

// 매핑 결과가 null이 아닌 것만 가져오고 싶은 경우
val values = fruits.filter { it.name == "사과" }
    .mapNotNull { it.nullOrValue() }                   

2. 다양한 컬렉션 처리 기능

// 과일이 모두 사과인가?
val isAllApple = fruits.all { it.name == "사과" }
// 사과가 하나도 없는가
val isNotApple = fruits.none { it.name == "사과" }
// 10000원 이상인게 하나라도 있는가
val isNoApple = fruits.any { it.factoryPrice >= 10000 }
// 현재가로 오름차순 정렬
val sortedFruits = fruits.sortedBy { it.currentPrice }

// 현재가로 내림차순 정렬
val sortedFruits = fruits.sortedByDescending { it.currentPrice }
// 이름 기준 중복 제거 후 이름만 추출
val distinctFruitNames = fruits.distinctBy { it.name }
    .map { it.name }

3. List를 Map으로

// 이름 -> List<과일>
val map: Map<String, List<Fruit>> = fruits.groupBy { it.name }

// id -> 과일
val map: Map<Long, Fruit> = fruits.associateBy { it.id }

// 이름 -> List<출고가>
val map: Map<String, List<Long>> = fruits 
  .groupBy({ it.name }, { it.factoryPrice })
  
// id -> 출고가
val map: Map<Long, Long> = fruits 
  .associateBy({ it.id }, { it.factoryPrice })
val map = fruits.groupBy { it.name } 
  .filter { (key, value) -> key == "사과" }

4. 중첩된 컬렉션 처리

// 중첩 리스트에서 현재가와 출고가가 같은 과일 필터링
val samePriceFruits = fruitsInList.flatMap { list -> 
  list.filter { it.factoryPrice == it.currentPrice }
}
data class Fruit( ... ) {
  val isSamePrice: Boolean // 가격이 같은지 판별하는 커스텀 게터 구현
    get() = factoryPrice == currentPrice
}

// List<Fruit>에 isSamePrice를 호출하는 확장 함수 구현 
val List<Fruit>.samePriceFilter: List<Fruit>
  get() = this.filter(Fruit::isSamePrice)

// 최종 형태
val samePriceFruits = fruitsInList.flatMap { it.samePriceFilter }
val fruits = fruitsInList.flatten()