제네릭과 배열 (3/3)
Do it! 코틀린 프로그래밍 [셋째마당, 코틀린 표준 라이브러리의 활용] 학습
✏️2. 배열 다루기✏️
배열(Array)
- 동일한 자료형의 데이터를 연속적으로 나열한 형태
- 순서 번호에 해당하는 인덱스(Index)와 값이 들어 있는 자료형에 따른 요소의 저장공간을 가짐
- 코틀린에서는 요소에 여러 가지 자료형을 혼합해 구성할 수 있음
2-1. 배열을 사용하는 방법
📌 기본적인 배열 표현
- 기본적인 배열을 생성하기 위해서는
arrayOf()
나Array()
생성자를 사용 - 빈 상태의 배열을 지정하는 경우
arrayOfNulls()
를 사용
val numbers = arrayOf(4, 5, 6, 7) // 정수형으로 초기화된 배열
val animals = arrayOf("Cat", "Dog", "Lion") // 문자열형으로 초기화된 배열
for (element in numbers) { } // 정숭형으로 초기화된 배열 출력
📌 다차원 배열
- 기본적인 배열을 묶어서 2차원 이상의 배열로 표현하는 형태
val array1 = arrayOf(1, 2, 3)
val array2 = arrayOf(4, 5, 6)
val array3 = arrayOf(7, 8, 9)
val arr2d = arrayOf(array1, array2, array3)
// 간략화 한 선언 방법
val arr2d = arrayOf(arrayOf(1, 2, 3), arrayOf(4, 5, 6), arrayOf(7, 8, 9))
📌 배열에 여러 가지 자료형 혼합하기
-
특정 자료형으로 제한하지 않는다면 배열의 요소로 정수, 문자열, 불린 등 여러가지 자료형을 혼합할 수 있음
->val mixArr = arrayOf(4, 5, 6, "Chike", false)
-
특정 자료형으로 제한하려면
arrayOf<자료형 이름>()
형태나자료형 이름 + ArrayOf()
형태의 조합으로 나타낼 수 있음
->val intOnlyArr1 = arrayOf<Int>(4, 5, 7, 3)
->val intOnlyArr2 = intArrayOf(4, 5, 7, 3)
-
자료형 + ArrayOf() 형태 조합의 종류
->longArrayOf()
shortArrayOf()
byteArrayOf()
등..
📌 배열 요소에 접근하기
- Array클래스는 게터/세터 를 가지고 있음
- 대괄호를 사용해 접근할 수 있는데 이것은 연산자 오버로딩으로 정의되어 있기 때문
arr.get(index) -> value = arr[index]
arr.set(index) -> arr[index] = value
⬇️ 배열 요소에 접근 (get)
val arr = intArrayOf(1, 2, 3, 4, 5)
println(arr.get(2)) // 게터를 통한 접근
println(arr[2]) // 연산자 오버로딩으로 대괄호를 통한 접근
// 다차원 배열의 요소에 접근
println(arr2d[2][1])
⬇️ 배열 요소에 접근 (set)
arr.set(2, 7)
arr[0] = 8
arr2d[2][1] = 2
📌 표현식을 통해 배열 생성하기
val|var 변수 이름 = Array(요소 개수, 초깃값)
val arr3 = Array(5, {i -> i * 2})
-> arr3의 요소는 [0, 2, 4, 6, 8]
2-2. 배열 제한하고 처리하기
- 배열은 정의되면 배열의 길이와 내용이 메모리에 고정
-> 선언된 배열을 잘라내거나 덧붙일 수 없음 - 고정되지 않은 동적인 배열이 필요하다면
List
를 사용해야 함
📌 배열에 요소 추가하고 잘라내기
val arr1 = intArrayOf(1, 2, 3, 4, 5)
val arr2 = arr1.plus(6) // 하나의 요소를 추가한 새 배열 생성
val arr3 = arr1.sliceArray(0..2) // 필요한 범위를 잘라내 새 배열 생성
-> arr2는 [1, 2, 3, 4, 5, 6] , arr3는 [1, 2, 3]
📌 기타 배열 관련 API 사용하기
arr.first() // 첫 번째 요소 확인
arr.last() // 마지막 요소 확인
arr.indexOf(3) // 3번째 요소 확인
arr.average() // 배열의 평균 값 출력
arr.count // 요소의 개수 세기 (배열의 크기)
arr.reversedArray() // 요소의 순서를 뒤집기
arr.sum() // 요소를 합산
arr.contains() // 배열에 특정 요소가 포함되어 있는지 확인
// -> 지정한 요소가 포함되어 있다면 true를 반환
📌 Any로 선언된 배열
- Any 자료형으로 만들어진 배열은 기존 자료형을 다른 자료형으로 지정할 수 있음
fun main() {
val b = Array<Any>(10,{0})
b[0] = "Hello World"
b[1] = 1.1
}
-> 처음에는 배열의 모든 요소가 정수형이었으나 할당한 값에 따라 요소의 자료형이 변환
📌 멤버 메서드를 통한 배열 순환하기
- 배열의 멤버 메서드인
forEach()
와forEachIndexed()
를 사용해 요소 순환 가능 forEach()
: 요소 개수만큼 지정한 구문을 반복 실행forEachIndex()
: 순환하며 인덱스까지 출력
arr.forEach { element -> print("$element ") }
// 인덱스는 i로 요소는 e로 받아 오른쪽으로 구문으로 넘김
arr.forEachIndexed({ i, e -> print("arr[$i] = $e") })
iterator()
: 반복을 위한 요소를 처리하는 메서드
val iter: Iterator<Int> = arr.iterator()
while(iter.hasNext()) { // hasNext() : 다음 요소가 있는지 확인
val e = iter.next() // next() : 다음 요소를 반환
}
2-3. 배열 정렬하기
📌 기본배열 정렬하고 반환하기
- Array는 기본적인 정렬 알고리즘을 제공
sortedNums()
sortedNumsDesc()
-> 원본 배열에 정렬을 수행하지 않고 새로운 배열을 생성하여 할당sort(fromIndex,toIndex)
sortedNumsDesc()
-> 원본 배열에 대한 정렬
-> 인자를 지정하면 특정 구간만 배열 가능. 인자 미지정시 전체 요소를 대상으로 정렬sorted()
sortedDescending()
-> 배열이 아닌 List로 반환sortBy {}
-> 특정 표현식을 넣어 정렬
fun main() {
val arr = arrayOf(8, 5, 1, 9, 4)
val sortedNums = arr.sortedArray()
val sortedNumsDesc = arr.sortedArrayDescending()
arr.sort(1, 3)
arr.sortDescending()
val listSorted: List<Int> = arr.sorted()
val listDesc: List<Int> = arr.sortedDescending()
val items = arrayOf<String>("Dog", "Cat", "Lion", "Kangaroo", "Po")
// 글자수가 짧은것부터 정렬
items.sortBy { item -> item.length }
}
📌 sortBy()로 데이터 클래스 정렬하기
- 멤버 변수에 따라 정렬 가능
data class Product(val name: String, val price: Double)
fun main() {
val products = arrayOf(
Product("one", 10.0),
Product("two", 40.0),
Product("three", 20.0)
)
// price가 제일 낮을 것을 기준으로 오름차순 정렬
// 인자가 람다식 1개여서 소괄호 () 생략
products.sortedBy { it.price }
}
📌 sortWith() 비교자로 정렬하기
- Comparator는 자바의 인터페이스로서 2개의 객체를 구현하는
compare()
를 구현
products.sortWith(
//Comparator 객체를 이용해 o1이 o2보다 크면 1, 같으면 0, 작으면 -1
Comparator<Product> { o1, o2 ->
when {
o1.price > o2.price -> 1
o1.price == o2.price -> 0
else -> -1
}
}
)
// 이름 순으로 정렬 후 가격순으로 정렬
products.sortWith(compareBy({ it.name }, { it.price }))
📌 배열 필터링하기
filter()
메서드를 활용하여 원하는 데이터를 골라 낼 수 있음
fun main() {
val fruits = arrayOf("banana", "apple", "avocado", "kiwi")
// 메서드 체이닝
fruits
.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { println(it) }
}
-> filter() 메서드를 사용해 a로 시작하는 요소만 골라냄
-> sortedBy 로 배열을 오름차순으로 정렬
-> map으로 받아 대문자로 변경 후 출력
📍메서드 체이닝(Method Chaining)
- 메서드를 연속해서 호출하는 방법
- 코드를 간결하게 작성할 수 있음
- 각 결과를 it으로 넘겨받아 처리할 수 있어 유용함
- 특정 메서드에서 오류가 나면 디버깅하기 어려워짐
- 초반 메서드에서 오류가 발생하면 후반 메서드는 작동하지 않아 '열차 사고'에 비유하기도 함
2-4. 배열 평탄화 하기
- 배열 평탄화(flatten) : 다차원 배열을 단일 배열로 만드는 것
flatten()
메서드를 이용
fun main() {
val numInt = arrayOf(1, 2, 3)
val numString = arrayOf("one", "two", "three")
// 2차원 배열
val simpleArray = arrayOf(numInt, numString)
// 단일 배열로 평탄화
val flattenSimpleArray = simpleArray.flatten()
}
-> flattenSimpleArray는 [1, 2, 3, "one", "two", "three"] 형태의 단일 배열로 변환됨
✏️3. 문자열 다루기✏️
3-1. 문자열의 기본 처리
- 문자열은 연속된 문자의 배열과 같음
- 불변(immutable)값으로 생성되기 떄문에 참조되고 있는 메모리가 변경될 수 없음
- 새로운 값을 할당하려고 한다면 기존 메모리 이외에 새로운 문자열을 위한 메모리를 만들어 할당해야함
-> 기존 사용하던 메모리 공간은 GC(Garbage Collector)에 의해 제거
-> GC에 의한 제거시점은 프로그래머가 제어할 수 없음 따라서 대량의 문자열을 다룰 떄는 메모리의 낭비가 일어나지 않도록 주의해야함
val hello: String = "Hello World!"
println(hello[0]) // H
hello[0] = 'K' // !오류!
hello = "bye" // 새로운 메모리 공간이 생성
📌 문자열 추출하고 병합하기
- 문자열은 배열이기 때문에 인덱스로 특정 범위의 문자열을 추출할 수 있음
String.substring(인덱스 범위 지정): String
CharSequence.subSequence(인덱스 범위 지정): CharSequence
s = "abcdef"
s.substring(0..2) // 인덱스 0~2 범위인 abc 반환
// 문자열의 추출 및 병합
s = s.substring(0..1) + "x" + s.subString(3..s.length-1) // abxdef반환
-> s에는 새로운 문자열이 할당되며 "abcedf"는 어딘가 남아있다가 GC에 의해 제거됨
📌 문자열 비교하기
compareTo()
메서드를 사용하여 문자열을 비교 할 수 있음
var s1 = "Hello Kotlin"
var s2 = "Hello KOTLIN"
println(s1.compareTo(s2)) // false 반환
println(s1.compareTo(s2, true)) // 대소문자 무시, true 반환
📌 StringBuilder 사용하기
- StringBuilder를 사용하면 문자열이 사용할 공간을 좀 더 크게 잡을 수 있음
- 기존의 문자열보다는 처리속도가 느림
- 단어를 변경하지 않고 그대로 사용하면 임시 공간인 메모리가 낭비됨
- 문자열이 자주 변경되는 경우에 사용하는것이 좋음
var s = StringBuilder("Hello")
s[2]='x' // 문자열에선 허용되지 않았던 요소의 변경이 가능! Hexlo
-> s는 메모리 공간을 새롭게 만들어지지 않고 여유분의 공간을 이용해 문자 요소가 변경
- StringBuilder의 기타 관련 메서드를 사용하면 포함(append), 추가(insert), 삭제(delete)가 용이해짐
- 문자열을 포함시키기 위해 사용하는
append()
는 생성된 버퍼를 사용하므로 보통 + 연산자를 이용해 새로운 객체를 만들어 처리하는것보다 더 좋음
s.append("World") // HexloWorld
s.insert(10, "Added") // HexloWorldAdded
s.delete(5, 10) // HexloAdded
Author And Source
이 문제에 관하여(제네릭과 배열 (3/3)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@zzangdd/제네릭과-배열-33저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)