리스트는 배열과 다르게 길이에 대한 제약이 없으며 중간에 값이 빠지더라도 메모리를 차지하지 않습니다.
1억개의 값을 각각 배열과 리스트에 넣어주었을 때, 배열은 그 중에서 9천만개를 지운다면 천만개의 값과 9천만개의 빈공간이 남아 메모리를 차지합니다.
반면 리스트는 9천만개의 공간을 없애고 천만개만큼의 자리만 차지합니다.
이처럼 값의 삭제나 수정 등이 빈번하게 필요하다면 배열보다는 리스트를 사용하는 것이 좋습니다.
자바에서는 다음과 같이 리스트를 만들어주었습니다.
import java.util.*
public class Main {
public static void main(String[] args) {
List list = new ArrayList<>();
// 값을 넣어줄 때
list.add(123)
// 값을 삭제할 때
list.remove()
// 값을 조회할 때
list.get()
}
}
List
란?코틀린에서는 listOf
를 사용해서 리스트를 만들어줍니다.
fun main(args: Array<String>) {
var numbers:List<Int> = listOf<Int>( 1, 2, 3, 4, 5 )
}
자료형이 List
이고 제네릭에 Int
를 선언했기 때문에 정수형만 올 수 있습니다.
이 리스트에 있는 값들을 하나씩 출력해주기 위해서는 for
루프를 사용합니다.
fun main(args: Array<String>) {
var numbers:List<Int> = listOf<Int>( 1, 2, 3, 4, 5 )
for(num in numbers) {
println("$num")
}
}
문자열만 받는 리스트는 제네릭을 String
으로 해주면 됩니다.
fun main(args: Array<String>) {
var numbers:List<String> = listOf<String>( "one", "two", "three" )
for(num in numbers) {
println("$num")
}
}
리스트의 크기는 size
로 확인합니다.
fun main(args: Array<String>) {
var numbers:List<Int> = listOf<Int>( 1, 2, 3, 4, 5 )
println(numbers.size)
}
값을 조회하는 방법은 다음과 같은 메서드를 사용하는 것입니다.
fun main(args: Array<String>) {
var numbers:List<String> = listOf<String>( "one", "two", "three" )
println(numbers.get(1))
// 또는
println(numbers[1])
// 결과는 two
}
fun main(args: Array<String>) {
var numbers:List<String> = listOf<String>( "one", "two", "three" )
println(numbers.indexOf("two")) // 1
}
fun main(args: Array<String>) {
val fruits = listOf("apple", "banana", "kiwi")
for(item in fruits) println(item)
for(index in fruits.indices) println("fruits[$index] : ${fruits[index]}")
}
fun main(args: Array<String>) {
val fruits = listOf("apple", "banana", "kiwi")
var findIndex = -1 // 값을 못찾는 경우를 대비해 -1로 초기화
for (i in 0..fruits.size - 1 step(1)) {
if (fruits.get(i) === "banana") {
findIndex = i
break
}
}
println(fruits[findIndex])
}
리스트 내 조회할 값의 포함여부를 boolean으로 반환해줍니다.
fun main(args: Array<String>) {
var numbers:List<String> = listOf<String>( "one", "two", "three" )
println(numbers.contains("two")) // true
}
리스트에 정해진 자료형만 들어가는 것은 아닙니다.
fun main(args: Array<String>) {
var mixedType = listOf("hello", 123, true, 123.456)
for(m in mixedType) print("$m ")
println()
}
제네릭을 선언해주지 않으면 다양한 자료형을 리스트에 담을 수 있습니다.
앞서 자바에서 리스트를 생성한것처럼 빈 리스트를 생성하고자 한다면
fun main(args: Array<String>) {
var emptyList = emptyList<String>()
}
emptyList
로 생성해줄 수 있습니다.
null
이 아닌 element만 리스트에 담기어떤 리스트에 null
이 들어있다면 이 null
을 필터링해서 null
이 아닌 값만 담아줄 수 있는 리스트가 있는데, 바로 listOfNotNull
입니다.
fun main(args: Array<String>) {
val notNullList:List<Int> = listOfNotNull(2, 3, 4, null, 5, 7, null) //이라면
println(notNullList) // null은 반영되지 않음
println(notNullList[3])
}
ArrayList
물론 코틀린에서도 ArrayList
를 사용할 수 있습니다.
listOf
로 선언한 리스트를 값의 수정이나 삭제가 불가능한 배열과 비슷한 존재이기 때문에 값의 수정이나 삭제가 필요하다면 ArrayList
를 사용해야 합니다.
fun main(args: Array<String>) {
val strList:ArrayList<String> = arrayListOf<String>("hello", "world", "success")
}
자바의 ArrayList
와 동일합니다.
fun main(args: Array<String>) {
val strList:ArrayList<String> = arrayListOf<String>("hello", "world", "success")
strList.add("kotlin")
strList.get(1) // hello
strList.set(1, "hi")
strList.remove(2)
}
가변형 리스트는 지금부터 소개할 mutableList
입니다. 반대말은 불변형 리스트이며 앞에서 살펴본 listOf
로 선언된 리스트를 말합니다.
불변형 리스트는 가변형 리스트에 비해 리스트의 인덱스에 있는 원소에 접근하는 속도가 다소 빠릅니다.
한편 가변형 리스트는 새로운 원소를 추가할 때 추가적인 메모리 공간이 필요하기 때문에 메모리 효율 측면에서는 다소 떨어집니다.
그러므로 Kotlin에서 리스트를 사용할 때, 리스트를 수정해야한다면 불변형 리스트를 가변형 리스트로 바꿔주고 변경이 완료되었다면 다시 불변형 리스트로 바꿔주는 것이 좋습니다.
fun main(args: Array<String>) {
// 선언
val mutableListNames:MutableList<String> = mutableListOf<String>("kim", "lee", "yun")
mutableListNames.add("park") // insert
println(mutableListNames)
mutableListNames.removeAt(2) // delete(인덱스로 삭제)
println(mutableListNames)
mutableListNames[0] = "choi" // update
// 또는 .set()
println(mutableListNames)
}
fun main(args: Array<String>) {
// 가변형 리스트를
var names:List<String> = listOf<String>("one", "two", "three")
// 불변형 리스트로
val newNames = names.toMutableList()
newNames.add("five")
println(newNames)
}
class Duck(val name:String, val age:Int)
이 클래스를 리스트의 제네릭으로 지정해주고 값을 넣어보겠습니다.
fun main(args: Array<String>) {
val list:MutableList<Duck> = mutableListOf()
val duck = Duck("오리1", 2)
list.add(duck)
list.add(Duck("오리2", 2))
list.add(Duck("오리3", 4))
for (d in list) {
println(d.name)
}
}
Map
Map
이란?보통의 리스트는 인덱스당 하나의 값이 들어가는 구조라고 한다면 맵은 key
와 value
가 한 쌍이 되어 하나의 인덱스를 차지합니다.
뿐만 아니라 값을 조회할 때 보통의 리스트는 인덱스를 기준으로 조회하지만 맵은 key
값으로 value
를 조회합니다.
fun main(args: Array<String>) {
val langMap:Map<Int, String> = mapOf( 1001 to "kotlin", 1002 to "Java", 1003 to "react" )
for ( (key, value) in langMap ){
println("key=$key, value=$value")
}
println(langMap[1002]) // key가 1002인 값 조회
println(langMap.get(1001)) // key가 1001인 값 조회
println(langMap) // {1001=kotlin, 1002=Java, 1003=react}
println(langMap.keys) // [1001, 1002, 1003] --> key값만 조회
}
langMap
은 key
와 value
를 갖는 해쉬맵입니다. 리스트와 마찬가지로(listOf
) mapOf
로 선언되었기 때문에 불변형 Map입니다.
Map
가변형 Map
은 가변형 List
와 같은 개념입니다. 불변형 맵은 값의 수정, 삭제가 안되기 때문에 수정이나 삭제가 필요하다면 가변형 맵으로 바꿔주어야 합니다.
아예 가변형 맵으로 생성하는 방법도 있습니다. 그리고 두개의 해쉬맵을 합쳐줄 수도 있습니다.
fun main(args: Array<String>) {
// 생성
val capitalCityMap:MutableMap<String, String>
= mutableMapOf("Korea" to "Seoul", "China" to "Beijing", "Japan" to "Tokyo")
// 전체 출력
println(capitalCityMap) // {Korea=Seoul, China=Beijing, Japan=Tokyo}
// key값만 출력
println(capitalCityMap.keys) // [Korea, China, Japan]
// value만 출력
println(capitalCityMap.values) // [Seoul, Beijing, Tokyo]
// key-value 추가
capitalCityMap.put("UK", "London")
// china 삭제
capitalCityMap.remove("China")
// 삭제 후 출력
println(capitalCityMap) // {Korea=Seoul, Japan=Tokyo, UK=London}
// capitalCityMap과 addData 합치기
val addData = mutableMapOf("USA" to "Washington", "India" to "NewDelhi")
// capitalCityMap을 pullAll메서드로 addData와 합치기
capitalCityMap.putAll(addData)
// 출력
println(capitalCityMap) // {Korea=Seoul, Japan=Tokyo, UK=London, USA=Washington, India=NewDelhi}
}
해쉬맵에는 정렬 기능이 있습니다. 위에서 만들어준 capitalCityMap
을 오름차순과 내림차순으로 각각 정렬해보겠습니다.
오름차순 정렬을 위해서는 sortedBy
를 사용하며, 내림차순 정렬 시에는 sortedByDescending
을 사용합니다.
fun main(args: Array<String>) {
// 오름차순 정렬
//var sortedByValue = capitalCityMap.toList().sortedBy { it.first }
// 내림차순 정렬
var sortedByValue = capitalCityMap.toList().sortedByDescending { it.first }
println(sortedByValue) // [(USA, Washington), (UK, London), (Korea, Seoul), (Japan, Tokyo), (India, NewDelhi)]
}
이 때 { it.first }
는 iterator
즉 반복을 나타내며 첫번째 값을 기준으로 정렬을 반복하겠다는 의미가 됩니다.