Collection에서 사용할 수 있는 여러가지 유용한 함수들
지금까지 우리는 collection을 for을 사용하여 하나하나 꺼내면서 사용했다. 하지만, kotlin은 함수형 언어이기 때문에, 즉 순수함수를 사용하여 반복문과 같은 불필요한 코드를 줄일 수 있기 때문에 편리한 코드를 작성할 수 있다. 즉 매우매우 중요한 개념이라는 뜻이다.
collection 함수는 list나 set, map과 같은 collection 또는 배열에 일반함수 또는 람다함수 형태를 이용하여 for문 없이도 아이템을 순회하여 참조하거나 조건을 걸고, 구조의 변경까지 가능한 여러 가지 함수를 지칭한다.
예시
forEach
collection.forEach {
println(it)
}
단순히 반복만 하는 함수도 있지만, 특정한 조건을 걸 수도 있다
filter
collection.filter {
println(it < 4)
}
map
collection.map {
println(it * 2)
}
any
, all
, none
collection.any { it == 0 } // 하나라도 맞으면 true
collection.all { it == 0 } // 모두 맞으면 true
collection.none { it == 0 } // 하나도 조건에 맞지 않으면 true
first
collection.first() // 첫번째 아이템을 반환
collection.first { it > 3 } // 조건에 맞는 첫번째 아이템 반환
collection.last { it > 3 } // 조건에 맞는 마지막 아이템을 반환 last
first
→ find
last
→ findLast
이때 first와 last는 사용시 문제가 생길수도 있다. 바로 조건에 맞는 객체가 없는 경우 NoSuchElementException이 발생할 수 있다. 이때는 firstOrNull 또는 lastOrNull를 사용하면, 객체가 없는 경우 null을 반환해준다.
count
collection.count(찾고가 하는 이름) // 개수를 다 세준다.
collection.count{ it > 7 } // 조건에 맞는 아이템 개수 반환
이러한 코틀린의 collection은 반복문이나 조건문을 사용하는 코드를 대부분 대체할 수 있다는 장점이 있다.
fun main() {
val langList = listOf("kotlin", "python", "java", "javascript", "C", "C++", "C#")
langList.forEach { println(it + " ")}
println() // 각 언어의 이름 모두 출력
println(langList.filter{ it.startsWith("j") }) // j로 시작하는 것만 출력
println(langList.map{ it + " language" }) // it뒤에 language 붙이기
println(langList.any { it == "kotlin" }) // kotlin이 있으면 true
println(langList.all { it.length == 6 }) // it의 길이가 모두 6이면 true
println(langList.none { it.startsWith("d")}) // d로 시작하는 게 없으면 true
println(langList.first { it.startsWith("C") }) // C로 시작하는 가장 첫번째 원소
println(langList.last { it.startsWith("C") }) // C로 시작하는 가장 마지막 원소
println(langList.count { it.contains("k") }) // k가 포함된 원소의 개수
}
이렇게 컬랙션 함수는 람다 함수를 사용하여 컬렉션을 더 편하게 조작할 수 있는 장점을 가진 함수로 경우에 따라 반복문과 조건문 대신 사용하면, 아주 편리한 코드를 작성할 수 있다.
associateBy
: 객체에서 key 추출하여 map으로 변환하는 함수
groupBy
: key가 같은 아이템 끼리 배열로 묶어 map으로 반환하는 함수
partition
: 아이템에 조건을 걸어 두개의 컬렉션으로 나눠준다. 이때 나눠진 두 컬렉션은 pair class로 반환된다. 따라서 각각의 collection을 first, second로 나눠서 참조한다. 이때 만약에 이렇게 하기 싫으면, 변수 이름을 설정하여 진행할 수 있다.
flatMap{}
: 아이템마다 만들어진 컬렉션을 합쳐서 반환하는 함수
getOrElse(){}
: 인덱스 위치에 아이템이 있으면, 아이템을 반환하고 아닌 경우 지정한 기본값을 반환하는 함수
zip
: 컬렉션 두 개의 아이템을 1:1로 매칭하여 새 컬렉션을 만들어 준다. 이때 결과 리스트의 아이템 개수는 더 작은 컬렉션의 개수를 따라가게 된다.
fun main() {
data class Coding(val name: String, val birthYear: Int)
val langList = listOf(Coding("c#", 2000),
Coding("kotlin", 2011),
Coding("Dart", 2011),
Coding("Python", 1991))
println(langList.associateBy{ it.birthYear })
println(langList.groupBy{ it.name })
val (over2010, under2010) = langList.partition{ it.birthYear > 2010 }
// 새로운 변수를 만들 때 조건 왼쪽이 참 오른쪽 거짓일 때의 partition이다.
println(over2010)
println(under2010)
val numbers = listOf(-3, 7, 2, -10, 1)
println(numbers.flatMap { listOf(it*10, it+10) })
println(numbers.getOrElse(1) {50}) // 인덱스 1번 아이템이 없으면 50을 반환
println(numbers.getOrElse(10) {50}) // 인덱스 10번 아이템이 없으면 50을 반환
val names = listOf("A", "B", "C", "D")
(names zip numbers).forEach{
println(it.first)
println(it.second)
}
}
개인적으로 zip은 파이썬에서 많이 봤는데, 너무 반가웠당... 이제는 진짜 코틀린을 마스터할 시간.. 열심히 공부하자!