컬렉션 함수형 API

한포도·4일 전
0

About Kotlin

목록 보기
6/6
post-thumbnail

컬렉션 함수형 API는.

함수형 프로그래밍 스타일을 사용하면 컬렉션을 다룰 때 편리합니다. 대부분의 작업에 라이브러리 함수를 활용할 수 있고 그로 인해 코드를 이주 간결하게 만들 수 있습니다.

1. 필수적인 함수: filter와 map

filter와 map은 컬렉션을 활용할 때 기반이 되는 함수입니다. 대부분의 컬렉션 연산을 이 두 함수를 통해 표현할 수 있습니다.

filter

먼저 숫자를 사용한 예제와 Person을 사용한 예제를 통해 살펴보겠습니다:

data class Person(val name: String, val age: Int)

val people = listOf(Person("Alice", 29), Person("Bob", 31))

val over30 = people.filter { it.age > 30 }
println(over30) // [Person("Bob", 31)]

filter 함수는 컬렉션을 이터레이션하면서 주어진 람다에 각 원소를 넘겨서 람다가 true를 반환하는 원소만 모읍니다.

map

map 함수는 주어진 람다를 컬렉션의 각 원소에 적용한 결과를 모아서 새 컬렉션을 만듭니다.

println(people.map { it.name }) // [Alice, Bob]
println(people.map { it.age }) // [29, 31]
println(people.map { it.age > 30 }) // [false, true]

filter와 map은 체이닝하여 자주 사용됩니다:

people.filter { it.age > 30 }.map { it.name }

2. 컬렉션 처리 함수 all, any, count, find

컬렉션의 모든 원소가 어떤 조건을 만족하는지 판단하거나 그 변종으로 컬렉션 안에 어떤 조건을 만족하는 원소가 있는지 판단하는 연산이 있습니다.

val canBeInClub27 = { p: Person -> p.age <= 27 }

// 모든 원소가 이 술어를 만족하는지
println(people.all(canBeInClub27))

// 술어를 만족하는 원소가 하나라도 있는지
println(people.any(canBeInClub27))

// 조건을 만족하는 원소의 개수
println(people.count(canBeInClub27))

// 조건을 만족하는 첫 번째 원소 찾기
println(people.find(canBeInClub27))

여기서 중요한 점은 count()size의 차이입니다:

// 이렇게 하면 중간 컬렉션이 생성됩니다
println(people.filter(canBeInClub27).size)

// count를 사용하면 중간 컬렉션이 생성되지 않습니다
println(people.count(canBeInClub27))

3. groupBy: 리스트를 여러 그룹으로 이뤄진 맵으로 변경

컬렉션의 모든 원소를 어떤 특성에 따라 여러 그룹으로 나누고 싶다면 groupBy를 사용합니다.

val people = listOf(Person("Alice", 31),
                   Person("Bob", 29),
                   Person("Carol", 31))
println(people.groupBy { it.age })
// 출력: {31=[Person(name=Alice, age=31), Person(name=Carol, age=31)],
//       29=[Person(name=Bob, age=29)]}

4. flatMap과 flatten: 중첩된 컬렉션 안의 원소 처리

flatMap

flatMap 함수는 두 가지 연산을 합친 함수입니다:

  1. 인자로 주어진 람다를 컬렉션의 모든 객체에 매핑(적용)하고
  2. 그 결과로 얻어지는 여러 리스트를 한 리스트로 모으는(flatten) 연산

예를 들어, 책에 대한 정보를 저장하는 도서관이 있다고 가정해봅시다:

class Book(val title: String, val authors: List<String>)

val books = listOf(
    Book("Thursday Next", listOf("Jasper Fforde")),
    Book("Mort", listOf("Terry Pratchett")),
    Book("Good Omens", listOf("Terry Pratchett", "Neil Gaiman"))
)

// 모든 저자의 집합을 얻기 위해 flatMap 사용
println(books.flatMap { it.authors }.toSet())
// 출력: [Jasper Fforde, Terry Pratchett, Neil Gaiman]

문자열 처리의 예:

val strings = listOf("abc", "def")
println(strings.flatMap { it.toList() })
// 출력: [a, b, c, d, e, f]

이 예제에서 람다 식 { it.toList() }는 각 문자열을 문자 리스트로 변환합니다. flatMap은 이런 리스트들을 단일 리스트로 반환합니다.

flatten

리스트의 리스트가 있는데 모든 중첩된 리스트의 원소를 평평하게 펼치기만 하면 된다면, 특별히 변환해야 할 내용이 없다면 flatten을 사용할 수 있습니다.

val listOfLists = listOf(listOf(1, 2, 3), listOf(4, 5, 6))
println(listOfLists.flatten())
// 출력: [1, 2, 3, 4, 5, 6]

사용시 주의사항

  1. 성능 최적화
    • 대용량 컬렉션을 처리할 때는 시퀀스 사용을 고려하세요
    • filter를 map 앞에 두어 불필요한 변환을 방지하세요
  2. 가독성
    • 너무 긴 체인은 가독성을 해칩니다
    • 적절히 중간 변수를 활용하세요
  3. 올바른 함수 선택
    • size 대신 count 사용하기
    • 상황에 맞는 특화된 함수 활용하기
    • 단순 flatten이 필요할 때는 flatMap 대신 flatten 사용하기

정리

  • 컬렉션 함수형 API를 사용하면 컬렉션 처리 코드를 더 간결하고 가독성 있게 작성할 수 있습니다.
profile
응애 개발맨
post-custom-banner

0개의 댓글