본문 바로가기

개발 노트/Kotlin

[kotlin]배열과 컬렉션

Int와 Double같은 타입은 모두 하나의 변수에 하나의 값만 저장하도록 되어있는데,

프로그래밍을 하다보면 하나의 변수에 여러개의 값을 저장해야할때가 있다

이처럼 여러개의 값하나의 변수에 저장할수있도록 배열(Array)컬렉션(Collection)이라는 데이터 타입을 제공한다

 

 

# 배열

- 여러개의 값을 담을 수 있는 대표적인 자료형

- 배열 공간의 개수를 할당하거나, 초기화시에 데이터를 저장해주면 데이터의 개수만큼 배열의 크기가 결정됨 

- 개수를 정해놓고 사용해야하며, 중간에 개수를 추가하거나 제거할 수 없다

 

var 변수 = Array(개수)

 

-> 배열은 다른 데이터 타입과 마찬가지로, 변수에 저장해서 사용할수있으며 위와같은 형태로 선언한다 

 

var students = IntArray(10)
var longArray = LongArray(10)
var CharArray = CharArray(10)
var FloatArray = FloatArray(10)
var DoubleArray = DoubleArray(10)

 

-> 배열 객체는 Int, Long, Char 등과 같은 타입 뒤에 Array를 붙여서 만든다

  • 첫번째 줄은 변수 studentsInt(정수형)공간을 10개 할당하라는 의미
  • students라는 이름으로 정수형 데이터를 담을수있는 10개의 공간을 가진 배열이 만들어지고, 각 공간에는 아직 무슨값이 들어있는지 모름
  • 인덱스를 사용해서, 10개의 공간을 가지는 위와 같은 배열의 인덱스는 0부터 시작해서 9에서 끝남(컴퓨터는 0을 첫번째로 인식함)

 

# 문자 배열에 빈공간 할당하기

 

- String은 Int, Double 등과 같은 기본 타입이 아니기 때문에 StringArray는 없지만, 다음과 같이 사용할 수 있다

var stringArray = Array(10, { item -> "" } )

 

-> 괄호안의 숫자인 10만 변경해서 사용하면, 그 숫자만큼 빈 문자열로 된 배열공간을 할당한다

 

 

 

# 값으로 배열공간 할당하기

 

- arrayOf 함수를 사용해서 String값을 직접 할당할수있다

var dayArray = arrayOf("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN")

 

 

 

# 배열에 값 입력하기

 

- 배열을 선언한 변수명 옆에 대괄호 [ ] 를 사용하고, 대괄호안에 값을 저장할 위치의 인덱스 번호를 작성한다. 그리고 등호를 사용해서 값을 입력할 수 있다

배열명[인덱스] = 값

 

 

- set 함수도 사용할 수 있다

- set 함수에 인덱스을 파라미터로 넘겨준다

배열명.set(인덱스, 값)

 

 

다음은 첫번째부터 열번째까지의 인덱스 값을 바꾸는 예제 코드이다

students[0] = 90
students.set(1, 91)
...
sutdents.set(8, 98)
students[9] = 99

 

-> students의 인덱스 0번째에 90을 넣고, 인덱스 1번째에는 91을 넣는다

-> students의 인덱스 8번째에 98을 넣고, 인덱스 9번째에는 99를 넣는다

 

 

# 여기서 잠깐!!

 - 배열의 범위를 벗어난 인덱스에 값을 넣을 경우에는 어떻게 될까??

  •   아래 예제와 같이, 10개의 공간이 할당된 배열에서 11번째에 해당하는 10번 인덱스에 값을 넣으려고하면, 범위를 넘어섰다는 Exception이 발생하고 프로그램이 종료된다
var intArray = IntArray(10)
intArray[10] = 100 			// Exception 발생. intArray의 마지막 인덱스는 9입니다.

--> ArrayIndexOutOfBoundsException 발생

 

 

 

 

# 배열에 있는 값 꺼내기

 

- 저장할 때와 마찬가지로, 대괄호안에 인덱스를 입력해서 값을 가져올 수 있으며, get()을 이용할수도 있다

배열명[인덱스]
배열명.get(인덱스)

 

var seventhValue = intArray[6]

 

-> 배열 intArray의 일곱번째값을 seventhValue 변수에 저장한다

 

var tenthValue = intArray.get(9)

 

-> 배열 intArray의 열번째 값을 get함수를 사용해서 tenthValue변수에 저장한다

 

 

 

아래는 예제 전체 코드이다

package net.flow9.thisiskotlin.basicsyntax

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. 기본타입 배열 선언하기 - 각 기본타입별로 10개의 빈 공간이 할당된다
        var students = IntArray(10)
        var longArray = LongArray(10)
        var CharArray = CharArray(10)
        var FloatArray = FloatArray(10)
        var DoubleArray = DoubleArray(10)
        // arrayOf를 사용하면 선언과 동시에 값을 입력할 수 있다
        var intArray = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        // intArray 변수에는 1 부터 10까지의 값이 각각의 배열공간에 저장되어 있다

        // 2. 문자열타입 배열 선언하기
        var stringArray = Array(10, { item -> "" })
        // arrayOf 함수로 값을 직접 입력해서 배열을 생성할 수 있다
        var dayArray = arrayOf("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN")

        // 3. 앞에서 선언한 studens 변수에 값 넣기
        // 가. 대괄호를 사용하는 방법
        students[0] = 90
        students[1] = 91
        students[2] = 92
        students[3] = 93
        students[4] = 94
        // 나. set 함수를 사용하는 방법
        students.set(5, 95)
        students.set(6, 96)
        students.set(7, 97)
        students.set(8, 98)
        students.set(9, 99)

        // 4. 값 변경해 보기
        intArray[6] = 137    // 6번 인덱스인 7번째 값 7이 137로 변경된다
        intArray.set(9, 200) // 9번 인덱스인 10번째 값 10이 200으로 변경된다

        // 5. 배열 값 사용하기
        var seventhValue = intArray[6]
        Log.d("Array", "7번째 intArray의 값은 ${seventhValue}입니다")
        var tenthValue = intArray.get(9)
        Log.d("Array", "10번째 intArray의 값은 ${tenthValue}입니다")

        Log.d("Array", "1번째 dayArray 값은 ${dayArray[0]}입니다")
        Log.d("Array", "6번째 dayArray 값은 ${dayArray.get(5)}입니다")
    }
}

/** [로그캣 출력 내용]
7번째 intArray의 값은 137입니다
10번째 intArray의 값은 200입니다
1번째 dayArray 값은 MON입니다
6번째 dayArray 값은 SAT입니다
*/

 

 

 

# 컬렉션

- 컬렉션(Collection)은 다른 이름으로는 "동적배열" 이라고도 한다

- 배열과는 다르게, 공간의 크기를 처음크기로 고정하지 않고, 임의의 개수를 담을 수 있기 때문이다

- 컬렉션은 크게 세가지로, 리스트(List), 맵(Map), 셋(Set) 이 있다

 

 

# 리스트(List)

- 리스트는 저장되는 데이터에 인덱스를 부여한 컬렉션이며, 중복된 값을 입력할수있다

- Kotlin에서 동적으로 리스트를 사용하기 위해서는 리스트 자료형 앞에 Mutable(뮤터블)이라는 접두어가 붙는다

- 예를 들면, mutableList, mutableMap, mutableSet 이 있다

- 배열과 같이 '데이터 타입Of" 형태로 사용할 수 있다

var list = mutableListOf("MON", "TUE", "WED")

 

 

 

 

# 여기서 잠깐!!

 - Mutable(뮤터블)이란??

  • Mutable(뮤터블)이란 "변할 수 있다" 라는 의미를 가지고 있다
  • kotlin은 컬렉션 데이터 타입을 설계할때 모두 immutable(이뮤터블: 변할수없는)으로 설계했다. 그래서 기본 컬렉션리스트(List), 맵(Map), 셋(Set)은 모두 한번 입력된 값을 바꿀 수 없다
  • 그래서 컬렉션의 원래 용도인 동적배열!! 로 사용하기 위해서는 Mutable(뮤터블)로 만들어진 데이터 타입을 사용해야한다

 

 

# 리스트 생성하기 : mutableListOf

 

- 다음과 같이 작성하면, 변수에 "MON", "TUE", "WED" 의 3개의 값을 가진 크기가 3동적 배열 리스트가 생성된다

var mutableList = mutableListOf("MON", "TUE", "WED)

 

 

 

# 리스트에 값 추가하기 : add

 

- add 함수를 사용해서 값을 추가할수있다

- 값이 추가되면, 동적으로 리스트의 공간이 자동으로 증가된다

mutableList.add("THU")

 

- add 함수를 사용하면, 입력될 위치인 인덱스를 따로 지정해주지 않아도 입력되는 순서대로 인덱스가 지정된다

-> "MON": [0], "TUE": [1], "WED": [2]   -->    "MON": [0], "TUE": [1], "WED": [2], "THU": [3]

 

 

 

# 리스트에 입력된 값 사용하기 : get

 

- get함수로 리스트에서 값을 꺼내서 사용할 수 있다

- 입력과는 다르게, 입력된 값을 사용할때는 인덱스를 지정해서 몇번째 값을 꺼낼것인지를 명시해야한다

var variable = mutableList.get(1)

 

-> 두번째 값을 꺼내서 variable이라는 변수에 저장한다

 

 

 

# 리스트값 수정하기 : set

 

set함수를 사용해서 특정 인덱스의 값을 수정할 수 있다

mutalbeList.set(1, "수정")

 

-> 두번째 값을 "수정" 으로 수정했다

 

 

 

# 리스트에 입력된 값 제거하기 : removeAt

 

- removeAt 함수로 리스트에 입력된 값의 인덱스를 지정해서 삭제할 수 있다

mutableList.removeAt(1)

 

-> 두번째 값을 삭제했다

-> 두번째 값을 삭제하면, 세번째 값부터 인덱스가 하나씩 감소하면서 빈자리의 인덱스로 이동한다

-> "MON": [0], "TUE": [1], "WED": [2]   -->    "MON": [0], "WED": [1]

     -> "TUE"가 삭제되면서 3번째값인 "WED"의 인덱스는 2에서 1로 바뀐다

 

 

 

# 빈 리스트 사용하기

 

- 아무것도 없는 빈 리스트를 생성하면, 앞으로 입력되는 값의 데이터타입을 알 수 없기 때문에 값의 타입을 추론할 수 없다

- 그래서 빈 컬렉션의 경우, 앞에서처럼 " 데이터타입Of "만으로는 생성되지 않고, 데이터타입을 직접적으로 알려주는 방법을 사용해야한다

var 변수명 = mutableListOf<컬렉션에 입력될 값의 타입>()
var stringList = mutableListOf<String>()

 

 

 

// 생성
var stringList = mutableListOf<String>()

// 입력
stringList.add("월")
stringList.add("화")

// 사용
Log.d("Collection", "stringList에 입력된 두 번째 값은 ${stringList.get(1)}입니다.")

// 수정
stringList.set(1, "수정된 값")

// 삭제
stringList.removeAt(1) // 두 번째 값이 삭제 됩니다.

 

-> 문자열로 된 빈 리스트를 생성하고 조작할 수 있다 

 

 

 

# 여기서 잠깐!!

 - 제네릭(Generic) 이란??

  • 리스트 컬렉션을 생성하면서 < > 괄호를 사용하는데, 이 괄호를 제네릭(Generic)이라고 한다
  • 제네릭(Generic)은 컬렉션이 사용하는 값의 타입을 지정하기 위한 도구이다 
  • kotlin에서 컬렉션은 제네릭을 사용하지 않으면 사용할 수 없다
  • 단, 값으로 초기화할때는 입력되는 값으로 타입을 추론할 수 있기때문에 이때는 제네릭을 쓰지 않아도 생성할 수 있다

 

 

# 컬렉션 개수 가져오기 : size

 

- size 프로퍼티를 사용하면 컬렉션의 개수를 가져올 수 있다 (mutableList.size)

- 위에서 set, get 등은 "함수" 라고 하고, size는 "프로퍼티"라는 용어를 사용했는데, 이 둘을 구분하는 방법은 괄호의 유무이다

  • 괄호가 있으면 -> 함수
  • 괄호가 없으면 -> 프로퍼티

 

package net.flow9.thisiskotlin.basicsyntax

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. 값으로 컬렉션 생성하기
        var mutableList = mutableListOf("MON", "TUE", "WED")
        // 값 추가하기
        mutableList.add("THU")
        // 값 꺼내기
        Log.d("Collection", "mutableList의 첫 번째 값은 ${mutableList.get(0)}입니다")
        Log.d("Collection", "mutableList의 두 번째 값은 ${mutableList.get(1)}입니다")

        // 2. 빈 컬렉션 생성하기기
        var stringList = mutableListOf<String>() // 문자열로 된 빈 컬렉션 생성
        // 값 추가하기
        stringList.add("월")
        stringList.add("화")
        stringList.add("수")
        // 값 변경하기
        stringList.set(1, "날짜 변경")
        // 사용
        Log.d("Collection", "stringList에 입력된 두 번째 값은 ${stringList.get(1)}입니다")
        // 삭제
        stringList.removeAt(1) // 두 번째 값이 삭제된다.
        Log.d("Collection", "stringList에 입력된 두 번째 값은 ${stringList.get(1)}입니다")
    }
}

/** [로그캣 출력 내용]
mutableList의 첫 번째 값은 MON입니다
mutableList의 두 번째 값은 TUE입니다
stringList에 입력된 두 번째 값은 날짜 변경입니다
stringList에 입력된 두 번째 값은 수입니다
*/

 

-> 컬렉션 List를 사용한 예제이다

 

 

 

 

# 셋 (Set) - mutableSetOf

- set "중복을 허용하지 않는" 리스트이다

- 리스트와 유사한 구조이지만 인덱스로 조회할 수 없고, get함수도 지원하지 않는다

- String 타입의 값을 입력받기 위해 다음과 같이 선언할 수 있다

var set = mutableSetOf<String>()

 

 

 

# 빈 Set으로 초기화하고 값 입력하기 

- set중복을 허용하지 않기 때문에 아래 코드를 보면, 네번째줄에서 입력한 "JAN"은 입력되지 않는다

var set = mutableSetOf<String>()
set.add("JAN")
set.add("FEB")
set.add("MAR")
set.add("JAN") // 동일한 값은 입력되지 않습니다.

 

 

 

# Set의 값 인덱싱?

- set은 인덱스로 조회하는 함수가 없기 때문에, 특정위치의 값을 사용할 수 없다 

 

 

 

# Set의 값 삭제하기 

- set은 값이 중복되지 않기 때문에, 아래와같이 값을 직접 입력하여 삭제해야된다 

set.remove("FEB")

 

 

 

package net.flow9.thisiskotlin.basicsyntax

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 1. 셋 생성하고 값 추가하기
        var set = mutableSetOf<String>()
        set.add("JAN")
        set.add("FEB")
        set.add("MAR")
        set.add("JAN") // 동일한 값은 입력되지 않는다.
        // 2. 전체 데이터 출력해보기
        Log.d("Collection", "Set 전체출력 = ${set}")
        // 3. 특정 값 삭제하기
        set.remove("FEB")
        Log.d("Collection", "Set 전체출력 = ${set}")
    }
}

/** [로그캣 출력 내용]
Set 전체출력 = [JAN, FEB, MAR]
Set 전체출력 = [JAN, MAR]
*/

 

-> 컬렉션 Set을 사용한 예제이다

 

 

 

 

# 맵(Map) - mutableMapOf

- Map키(key)와 값(Value)의 쌍으로 입력되는 컬렉션이다

- Map의 키는 리스트의 인덱스와 비슷한데, Map에서는 키를 직접 입력해야한다

- 제네릭으로 키와 값의 데이터타입을 지정해서 맵을 생성한다

 

var map = mutableMapOf<String, String>()

 

-> 키와 값의 타입을 모두 String으로 사용하기 위한 예제 코드이다

-> 인덱스에 해당하는 키를 직접 지정해서 사용해야한다

 

 

# 빈 Map으로 생성하고 값 추가하기 

- 값을 추가하기 위해, 맵에서 제공되는 put함수를 사용해서 키와 값을 입력하면 된다

var map = mutableMapOf<String, String>()
map.put("key1", "value2")
map.put("key2", "value2")
map.put("key3", "value3")

 

-> 키와 값을 추가할때마다 리스트처럼 맵의 공간이 늘어난다

 

 

 

# Map 사용하기 

- get 함수키를 직접 입력해서 값을 꺼낼 수 있다

Log.d("CollectionMap", "map에 입력된 key1의 값은 ${map.get("key1")}입니다.")

// [로그캣 출력 내용]
// map에 입력된 key1의 값은 value2입니다.

 

 

# Map 수정하기

- 입력할때와 같이 put함수를 사용해서 수정하는데 동일한 키를 가진값이 있으면, 키는 유지된 채로 그 값만 수정된다

 

map.put("key2", "수정")

 

-> 기존 "key2"의 값인 "value2"는 "수정"으로 바뀐다

 

 

# Map 삭제하기

- remove함수에 키를 입력해서 값을 삭제할 수 있다

- 리스트와는 다르게 인덱스에 해당하는 키의 값이 변경되지 않고, 그대로 유지된다

(삭제된다고해서 남아있는 인덱스의 값이 앞으로 옮겨가지 않음, 삭제되면 null값이 됨)

 

package net.flow9.thisiskotlin.basicsyntax

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 1. 맵 생성하기
        var map = mutableMapOf<String, String>()
        // 2. 값 넣기
        map.put("키1", "값2")
        map.put("키2", "값2")
        map.put("키3", "값3")
        // 3. 값 사용하기
        var variable = map.get("키2")
        Log.d("Collection", "키2의 값은 ${variable}입니다")
        // 4. 값 수정하기
        map.put("키2", "두 번째 값 수정")
        Log.d("Collection", "키2의 값은 ${map.get("키2")}입니다")
        // 5. 값 삭제하기
        map.remove("키2")
        // 5.1 없는 값을 불러오면 null값이 출력된다
        Log.d("Collection", "키2의 값은 ${map.get("키2")}입니다")
    }
}

/** [로그캣 출력 내용]
키2의 값은 값2입니다
키2의 값은 두 번째 값 수정입니다
키2의 값은 null입니다
*/

 

-> 컬렉션 Map을 사용한 예제

 

 

 

 

# 여기서 잠깐!!

 - 컬렉션 값의 단위 = 엘리먼트

  • 컬렉션에 입력되는 값 각각엘리먼트(Element) 라고 한다
  • 값이라고 해도 되지만 맵을 지칭할 때 맵의 값(엘리먼트 자체)를 가리키는건지, 엘리먼트의 값(실제값)을 가리키는 건지 2개의 용어가 충돌할 수 있기 때문에 엘리먼트라고 이해하는것이 좋다
  • 엘리먼트는 맵의 입력단위인 키와 값을 합친것을 말하는데, 이것은 리스트와 셋에서도 동일한 용어로 사용된다
  • 즉, 리스트의 값 또한 엘리먼트라고 부른다
  • -> 리스트 엘리먼트 = 리스트의 ()
  • -> 맵 엘리먼트 = 맵의 (키와 값)

 

 

 

# 이뮤터블 컬렉션 (Immutable Collection)

- kotlin은 일반 배열처럼 크기를 변경할 수 없으면서, 값 또한 변경할 수 없는 "이뮤터블 컬렉션"을 지원한다

- 이뮤터블 컬렉션은 다음과 같이 기존 컬렉션에서 mutable이라는 접두어가 제거된 형태로 사용된다

var list = listOf("1", "2")

 

- 불변형 컬렉션은 한번 입력된 값을 변경할 수 없기 때문에, add나 set함수는 지원하지 않고, 최초 입력된 값만을 사용할 수있다

- 배열과 다른 점은 크기뿐만 아니라, 값의 변경 또한 불가능하다는 것이다

- 즉, 불변형 컬렉션은 수정, 추가, 제거가 모두 안된다 

var immutableList = listOf("JAN", "FEB", "MAR") // 생성
Log.d("Collection", "리스트의 두 번째 값은 ${immtuableList.get(1)}입니다.) // 사용

// [로그캣 출력 내용]
// 리스트의 두 번째 값은 FEB입니다.

 

 

 

# 그러면 이뮤터블 컬렉션은 언제 사용할 수 있을까??

  • 일반변수 var과 읽기전용변수 val의 관계에서 이 사용법을 유추할 수 있는데, 기준이 되는 어떤 값의 모음을 하나의 변수에 저장할 필요가 있거나 또는 여러개의 값을 중간에 수정하지 않고 사용할 필요가 있을때 이뮤터블 컬렉션을 사용한다
  • 대표적인 예로 요일 데이터가 있다
  • -> 아래처럼 7개의 요일을 이뮤터블 리스트로 선언하면, 중간에 바뀌지 않기 때문에 계속 같은 값을 유지하면서 사용할 수 있다 
var dayList = listOf("월", "화", "수", "목", "금", "토", "일)

'개발 노트 > Kotlin' 카테고리의 다른 글

[kotlin]함수  (0) 2024.01.16
[kotlin]반복문  (0) 2024.01.16
[kotlin]조건문  (0) 2024.01.16
[kotlin]변수  (0) 2024.01.16
Log, Logcat  (0) 2024.01.16