해당 글은 코틀린 개발문서의 play example을 참고하였습니다. :)
List
package kotlincontents.collections
/*
List는 정렬된 콜렉션의 아이템입니다. List는 Mutable(변하는 List)되거나 읽기 전용(List)중 하나가 될 수 있습니다.
리스트를 생성할 때, std lib함수 listOf()는 읽기 전용의 리스트이며, mutableListOf()는 변경 가능한 리스트입니다.
원치 않은 수정을 방지하려면 변경 가능한 List로 캐스팅하여 읽기 전용으로 가져옵니다.
*/
val systemUsers: MutableList<Int> = mutableListOf(1, 2, 3) // 1
val sudoers: List<Int> = systemUsers // 2
fun addSystemUser(newUser: Int) { // 3
systemUsers.add(newUser)
}
fun getSysSudoers(): List<Int> { // 4
return sudoers
}
fun main() {
addSystemUser(4) // 5
println("Tot sudoers: ${getSysSudoers().size}") // 6
getSysSudoers().forEach { // 7
i -> println("Some useful info on user $i")
}
// getSysSudoers().add(5) <- Error! // 8
}
/*
1. MutableList 생성
2. 읽기 전용 List 생성
3. MutableList에 새로운 아이템 추가
4. 변하지 않는 list를 반환
5. MutableList를 업데이트, 모든 연관된(힙에 저장된 해당 데이터를 참조하고 있는) 읽기 전용 뷰들은
같은 오브젝트를 가리키는 동안에는 업데이트 되어집니다.
6. 읽기 전용의 리스트 사이즈를 검색
7. 리스트 반복 및 요소 출력
8. 읽기 전용 뷰에 쓰려고하면 컴파일 error가 발생합니다.
*/
Set
package kotlincontents.collections
/*
Set은 순서가 없는 컬렉션입니다. 해당 컬렉션은 중복을 허용하지 않습니다. Set을 생성할 때,
setOf()메서드와 mutableSetOf() 메서드를 호출합니다. mutable set을 Set으로 캐스팅 하여 가져올 수 있습니다.
*/
val openIssues: MutableSet<String> = mutableSetOf("uniqueDescr1", "uniqueDescr2", "uniqueDescr3") // 1
fun addIssue(uniqueDesc: String): Boolean {
return openIssues.add(uniqueDesc) // 2
}
fun getStatusLog(isAdded: Boolean): String {
return if (isAdded) "registered correctly." else "marked as duplicate and rejected." // 3
}
fun main() {
val aNewIssue: String = "uniqueDescr4"
val anIssueAlreadyIn: String = "uniqueDescr2"
println("Issue $aNewIssue ${getStatusLog(addIssue(aNewIssue))}") // 4
println("Issue $anIssueAlreadyIn ${getStatusLog(addIssue(anIssueAlreadyIn))}") // 5
}
/*
1. elements가 있는 Set 생성
2. 실질적으로 더해진 elements가 있다면 해당 Boolean값을 반환함
3. 파라미터로 함수의 결과에 기반한 string 반환
4. 성공 메시지 출력: 성공적으로 Set에 추가됨
5. 실패 메시지 출력: 중복된 element가 존재하므로 추가될 수 없음
*/
Map
package kotlincontents.collections
/*
A Map은 키/값 쌍으로 이루어진 컬렉션이다. 각 키는 고유하고 그에 상응하는 값을 검색하여 사용할 수 있다.
맵을 생성할 때 mapOf()함수와 mutableMapOf()로 생성
infix 메서드인 to를 사용하여 쉽게 초기화할수 있습니다.
이 역시 MutableMap를 Map으로 캐스팅하면 읽기 전용의 뷰로 가져올 수 있습니다.
*/
const val POINTS_X_PASS: Int = 15
val EZPassAccounts: MutableMap<Int, Int> = mutableMapOf(1 to 100, 2 to 100, 3 to 100) // 1
val EZPassReport: Map<Int, Int> = EZPassAccounts // 2
fun updatePointsCredit(accountId: Int) {
if (EZPassAccounts.containsKey(accountId)) { // 3
println("Updating $accountId...")
EZPassAccounts[accountId] = EZPassAccounts.getValue(accountId) + POINTS_X_PASS // 4
} else {
println("Error: Trying to update a non-existing account (id: $accountId)")
}
}
fun accountsReport() {
println("EZ-Pass report:")
EZPassReport.forEach { (k, v) -> // 5
println("ID $k: credit $v")
}
}
fun main() {
accountsReport() // 6
updatePointsCredit(1) // 7
updatePointsCredit(1)
updatePointsCredit(5) // 8
accountsReport() // 9
}
/*
1. MutableMap을 생성
2. 읽기 전용의 Map을 생성
3. Map의 키가 있는지 확인
4. 키에 상응하는 값을 읽고, 포함된 값을 증가시킴
5. 변경 불가한 Map을 Iterate하고, 키와 값의 쌍을 출력
6. account points balance를 읽고 (업데이트 전)
7. 존재하는 키의 account point를 업데이트
8. 존재하지 않는 계정값의경우 업데이트 시도 시 error message 출력
9. 현재 계정의 포인트를 read, (업데이트 후)
*/
filter
package kotlincontents.collections
/*
filter는 컬렉션의 필터링을 가능하게 해준다.
filter predicate(필터 조건자)를 람다식의 파라미터로써 사용합니다.
각 element에 조건을 적용합니다. elements는 조건이 true일때 이를 컬렉션 결과에 반환합니다.
*/
val numbers = listOf(1, -2, 3, -4, 5, -6) // 1
val positives = numbers.filter { x -> x > 0 } // 2
val negatives = numbers.filter { it < 0 } // 3
fun main() {
println(positives)
println(negatives)
}
/*
1. number 컬렉션을 정의
2. 양수를 필터링
3. it 노테이션으로 음수를 필터링
*/
map
package kotlincontents.collections
/*
map 확장 함수는 컬렉션의 모든 elements를 변형하여 적용시켜준다.
람다 파라미터로 함수를 변환합니다.
*/
val doubled = numbers.map { x -> x * 2 } // 2
val tripled = numbers.map { it * 3 } // 3
fun main() {
println(doubled)
println(tripled)
println(numbers)
}
/*
2. 2배가 적용된 numbers2 정의
3. it 표기법으로 간결하게 표기
*/
any, all, none
package kotlincontents.collections
/*
any all none 함순들은 주어진 조건자와 element를 매치해주는 컬렉션의 확장을 체크해주는 함수입니다.
*/
/**
** any **
any 함수는 조건이 주어졌을 때 적어도 하나의 element를 포함하고 있다면 true를 반환합니다.
즉, 조건에 맞는 element가 한개라도 있다면 true라는 의미
*/
val anyNegative = numbers.any { it < 0 } // 2
val anyGT6 = numbers.any { it > 6 } // 3
/**
* all함수는 조건자를 컬렉션에 매칭하여 모든 엘리먼트가 해당 조건에 부합한다면 true를 반환합니다.
*/
val allEven = numbers.all { it % 2 == 0}
val alless6 = numbers.all { it < 6 }
/**
* none함수는 조건이 주어졌을 때 컬렉션에 매칭하여 조건에 부합하는 엘리먼트가 단 한개도 없을 때 true를 반환합니다.
*/
val allEven_none = numbers.none { it % 2 == 1}
val alless6_none = numbers.none { it > 6 }
fun main() {
println(anyNegative)
println(anyGT6)
println(allEven)
println(alless6)
println(allEven_none)
println(alless6_none)
}
find, findLast
package kotlincontents.collections
/**
* find와 findLast 함수는 조건이 주어졌을 때 조건에 매칭하여 처음과 마지막 element를 반환합니다.
* 조건에 맞는 element가 단 한개도 없다면 null을 반환합니다.
*/
fun main() {
val words = listOf("Lets", "find", "something", "in", "collection", "somehow")
val first = words.find { it.startsWith("some") }
val last = words.findLast { it.startsWith("some") }
val nothing = words.find { it.contains("nothing")}
println(words)
println(first)
println(last)
println(nothing)
}
first, last
package kotlincontents.collections
/**
* 컬렉션에서 대응되는 처음과 마지막 element를 반환합니다.
* 조건자를 사용할 수도 있습니다. 만약 조건자를 주면 해당 조건에 맞는 first, last element를 반환합니다.
* (find, findLast 기능과 동일해짐)
*/
/**
* firstOrNull, lastOrNull 함수들은 위와 동일한 방식으로 동작하지만 한가지 다른점은
* 매칭되는 element가 없다면 null를 반환합니다.
*/
fun main() {
//
// val first = numbers.first()
// val last = numbers.last()
//
// val firstEven = numbers.first { it % 2 == 0 }
// val lastOdd = numbers.last { it % 2 == 1 }
//
// println(first)
// println(last)
//
// println(firstEven)
// println(lastOdd)
/* 만약 조건자를 주어서 first, last함수를 호출하는데 조건에 부합한 원소가 없다면 error가 발생합니다. */
val words = listOf("foo", "bar", "baz", "faz")
val empty = emptyList<String>()
val first = empty.firstOrNull()
val last = empty.lastOrNull()
val firstF = words.firstOrNull { it.startsWith('f') }
val firstZ = words.firstOrNull { it.startsWith('z') }
val lastF = words.lastOrNull { it.endsWith('f') }
val lastZ = words.lastOrNull { it.endsWith('z') }
println(first)
println(last)
println(firstF)
println(firstZ)
println(lastF)
println(lastZ)
}
count
package kotlincontents.collections
/*
count
count함수는 조건자에 맞는 elements의 수를 반환하거나 elements 전체의 수를 반환합니다.
*/
fun main() {
val numbers = listOf(1, -2, 3, -4, 5, -6)
val totalCount = numbers.count()
val evenCount = numbers.count { e ->
e % 2 == 0
}
println(evenCount)
}
associateBy, groupBy
package kotlincontents.collections
/*
associtateBy, groupBy
associateBy와 groupBy함수는 지정된 키에의해 인덱싱된 콜렉션의 elements로부터 map을 만듭니다.
키는 keySelector 파라미터로 정의되며, valueSelector옵션을 적용하여 맵의 element값에 저장할 값을 정의할 수 있습니다.
associateBy와 groupBy의 차이점은 동일한 키를 포함한 오브젝트를 어떻게 처리했느냐에 따라 달라집니다.
associateBy는 마지막으로 적합한 element를 값으로써 사용합니다.
groupBy는 리스트의 모든 적합한 elements를 뷜드하고 값에 넣습니다.
*/
data class Person(val name: String, val city: String, val phone: String) // 1
fun main() {
val people = listOf( // 2
Person("John", "Boston", "+1-888-123456"),
Person("Sarah", "Munich", "+49-777-789123"),
Person("Svyatoslav", "Saint-Petersburg", "+7-999-456789"),
Person("Vasilisa", "Saint-Petersburg", "+7-999-123456"))
val phoneBook = people.associateBy { it.phone } // 3
val cityBook = people.associateBy(Person::phone, Person::city) // 4
val peopleCities = people.groupBy(Person::city, Person::name) // 5
val lastPersonCity = people.associateBy(Person::city, Person::name) // 6
println(phoneBook)
println(cityBook)
println(peopleCities)
println(lastPersonCity)
}
/**
* 1. Person data 클래스 정의
*
* 2. people 콜렉션 정의
*
* 3. 각 폰 번호에 해당하는 Person객체를 map으로 뷜드하고, valueSelector는 제공되지 않으며,
* map의 값은 Person 오브젝트 자기 자신입니다.
*
* 4. owners가 살고있는 도시에 번호로부터 맵을 뷜드하고, 여기서 person::city는 valueSelector이며,
* 해당 map의 value는 도시만을 포함하고 있습니다.
*
* 5. 도시를 키로 갖는 map을 뷜드하며, 맵의 값은 person이름 리스트이다.(즉, 중복된 키를 고려하여
* 값이 List형태로 저장되는것 같습니다.
*
* 6. 마지막 사람이 포함된 키의 맵을 만듭니다. 이말은 머냐면 동일한 city값이 있다면 마지막 Person객체의 정보로
* 맵이 형성된다는 말이다. 따라서 값은 각 도시에 거주하는 마지막 사람의 이름입니다.
*/
partition
package kotlincontents.collections
/**
* The partition 함수는 original collection을 splits하여 pair of lists하는 함수입니다.
* 이때 조건자가 주어집니다.
*
* 1. 조건에 따라 true or false :: true면 first프로퍼티, false면 second프로퍼티
*/
fun main() {
val numbers = listOf(1, -2, 3, -4, 5, -6)
val evenOdd = numbers.partition { it % 2 == 0 }
val (positives, negatives) = numbers.partition { it > 0 }
println(numbers)
println("Even numbers: ${evenOdd.first}")
println("Odd numbers: ${evenOdd.second}")
println("Positive numbers: $positives")
println("Negative numbers: $negatives")
}
flatMap
package kotlincontents.collections
/**
* flatMap은 iterable object(반복 가능한 객체)로 각각의 컬렉션의 element를 변형한다. 그리고 하나의 list로 반환한다.
* 변형은 사용자가 정의해야 합니다.
*/
fun main() {
val fruitsBag = listOf("apple", "orange", "banana", "grapes")
val clothesBag = listOf("shirts", "pants", "jeans")
val cart = listOf(fruitsBag, clothesBag)
val mapBag = cart.map { it }
val flatMapBag = cart.flatMap { it }
val flatMapBag2 = cart.flatten()
println(fruitsBag)
println(clothesBag)
println(cart)
println(mapBag)
println(flatMapBag)
println(flatMapBag2)
}
minOrNull, maxOrNull
package kotlincontents.collections
/**
* minOrNull과 maxOrNull함수는 collection의 가장 큰 element와 작은 element를 반환한다.
* 단, 컬렉션이 비어있는 경우 null을 return한다.
*/
fun main() {
val numbers = listOf(1, 2, 3)
val empty = emptyList<Int>()
val only = listOf(3)
//
// println("Numbers: $numbers, min = ${numbers.minOrNull()} max = ${numbers.maxOrNull()}")
// println("Empty: $empty, min = ${empty.minOrNull()}, max = ${empty.maxOrNull()}")
// println("Only: $only, min = ${only.minOrNull()}, max = ${only.maxOrNull()}")
}
sorted
package kotlincontents.collections
import kotlin.math.abs
/**
* sorted는 기본적으로는 오름차순으로 정렬하여 컬렉션의 리스트형태로 반환합니다.
*
* sortedBy는 지정한 seletor함수의 반환 값에따라 정렬합니다.
*/
// 참고로 원본 리스트는 그대로고 정렬 할 때 조건을 주면 해당 조건이 적용된 리스트를 기준으로 원본 리스트를 정렬하는 거임.
fun main() {
val shuffled = listOf(5, 4, 2, 1, 3, -10)
val natural = shuffled.sorted()
val inverted = shuffled.sortedBy { -it }
val descending = shuffled.sortedDescending()
val descendingBy = shuffled.sortedByDescending { abs(it) }
println(natural)
println(inverted)
println(descending)
println(descendingBy)
}
Map Element Access
package kotlincontents.collections
/**
* 맵을 적용할 때 []operator는 주어진 키에 상응하는 값 또는 null을 반환합니다.(null의 경우 키가 없을경우)
* getValue함수는 주어진 키에 상응하여 존재하는 값을 반환하거나 키를 찾을 수 없을 때 예외를 던집니다.
*
* withDefault로 maps를 만들면, getValue를 return하게 될 경우 값이 없을 때 예외를 던지지 않고 default 값을 반환합니다.
*/
fun main() {
val map = mapOf("key" to 42)
val value1 = map["key"]
val value2 = map["key2"]
val value3: Int = map.getValue("key")
// 이 의미는 withDefault의 람다식은 키값이 존재하지 않으면 해당 키의 길이를 값으로써 defualt값을 설정한 것이다.
val mapWithDefault = map.withDefault { k -> k.length }
val value4 = mapWithDefault.getValue("key2")
println(value1)
println(value2)
println(value3)
println(value4)
try {
map.getValue("anotherKey")
} catch (e : NoSuchElementException) {
println("Message $e")
}
}
zip
package kotlincontents.collections
/**
* zip 함수는 주어진 2개의 컬렉션을 하나의 새로운 컬렉션으로 합치는 것입니다.
* 기본적으로, 동일한 인덱스를 가진 요소는 pair형태의 데이터로 되어있습니다.
* 그러나 해당 구조는 정의할 수 있습니다.
*/
fun main() {
val A = listOf("a", "b", "c")
val B = listOf(1, 2, 3, 4)
val resultPairs = A zip B
val resultReduce = A.zip(B) { a, b -> "$a$b"}
println(resultPairs)
println(resultReduce)
}
getOrElse
package kotlincontents.collections
/**
* getOrElse 함수는 컬렉션의 안전한 접근을 제공한다. default 값을 제공하는 인덱스와 함수가 필요하며,
* 만약 인덱스의 범위를 넘어설 경우 기본값을 반환합니다.
*/
fun main() {
val list = listOf(0, 10, 20)
println(list.getOrElse(1) { 42 })
println(list.getOrElse(10) { 42 }) // 인덱스 10은 컬렉션의 범위를 넘어섰으므로 기본값이 42를 반환
/** getOrElse는 키에대한 값이 주어졌을 때 map에도 적용할 수 있다. */
val map = mutableMapOf<String, Int?>()
println(map.getOrElse("x") { 1 })
map["x"] = 3
println(map.getOrElse("x") { 1 })
map["x"] = null
println(map.getOrElse("x") { 1 }) // 키가 존재해도 값이 null(정의되지 않음) 이므로 default값인 1이 반환!!
}
이상 마치겠습니다. :)
https://play.kotlinlang.org/byExample/05_Collections/01_List
Kotlin Playground: Edit, Run, Share Kotlin Code Online
play.kotlinlang.org