배열(Array)란?
Swft에서는 3개의 collection타입을 제공합니다. 그 중에서 오늘은 배열(Array)에 대해서 공부할 것입니다!!
배열에 타입(Int,String...)을 지정할 경우 이외의 타입을 삽입 할 수는 없습니다!!
그대신 컬랙션, 배열에서 검색할 값의 유형은 정해져 있다는 것!!
배열은 orderded list 순서가 있는 목록이에요.
index에 따라서 value를 저장할 수 있습니다.
Set과 Array의 차이점은?
우선 값의 중복 여부인데요.
Array는 value마다 고유의 index가 있기 때문에 값이 중복으로 저장 되어도 쉽게 구분 할 수 있습니다.
반면 Set의 경우 index 순서가 없기 때문에 출력 할 경우 무작위로 나옵니다. value의 중첩 삽입도 되지 않아 이미 Set에 특정 valueA가 있다면 추후 insert(valueA)를 할 때 튜플 (중복 여부 Bool타입 반환 , 삽입된 멤버)로 알 수 있습니다.
(cf : 배열의 타입은 generic collections로 구현 되어 있습니다.)
배열의 선언
배열을 선언 할 때 값을 수정하거나 삽입, 삭제 할 수 있도록 하거나 immutable하게 선언할 수 있습니다. ( 콜랙션이 그렇다네요 ~ )
- var로 선언할 경우에는 삽입, 삭제, 값 변경이 가능합니다.
- let로 선언할 경우에는 위의 값 변경이 불가능하고 크기도 변하지 않습니다.
왜 ? let으로 배열을 선언하는가? 값을 변경할 수도 없는데?
코드도 더 쉽게 판단할 수 있고 내가 생성한 배열,set,dictionary와 같은 컬랙션에 대해 컴파일러는 성능을 최적화 할 수 있기 때문
Swift에서 정의 된 배열은 Array<Element> 입니다.
여기서 Element는 배열의 데이터 타입을 의미합니다.
Array<Element>형식으로 선언하지 않고 [Element] 형식으로 간결하게 선언 할 수도 있습니다. 같은 표현, 의미입니다.
// 1. Element == Int로 배열의 선언만 할 경우
var array1 : Array<Int>
var array2 : [Int]
// 2. 위의 경우 반드시 초기화를 해주어야 한다.
array1 = Array<Int>() // array1 = [Int]()도 가능
array2 = [Int]() // array2 = Array<Int>() 로도 가능
// 3. 이렇게 선언과 초기화도 가능.
var arr3 : [Int] = []
// 4. size를 지정하면서 원하는 default value로 초기화도 가능.
var arr4 = Array(repeating: "haha", count: 3) // arr4 = ["haha","haha","haha"]
// 5. 리터럴 값들로도 default value 배열을 생성 할 수 있어요.
var arr5 = ["happy","Swift"]
// 6. 타입이 같다면 배열들을 + 한 새로운 배열도 선언 가능합니다.
var arr6 = arr4 + arr5 // ["haha","haha","haha","happy","Swift"]
1. 의 경우 선언만 한 경우입니다. 반드시 초기화를 해야 빈 배열이 형성됩니다. (초기화 안하면 사용 불가
2. 의 경우 초기화 작업입니다.
3. 처럼 선언 될 경우 배열의 변수 타입은 [Int] 초기화 타입으로 추론될 수 있기에 선언과 동시에 초기화 됨.
삽입과 삭제, 처음과 끝 원소 확인
배열의 삽입은
- Array.append(Element)
특정한 index에 값이 존재한다면 값 변경도 가능합니다.
- Array[index] = new Element
특정한 index에 값이 존재한다면 해당 index에 값을 삽입하고 싶은 경우
- Array.insert(new Element, at : index)
이때 해당 인덱스에 값이 교체가 아닌 삽입됨으로 기존 index부터 시작해 끝 까지 value들은 한칸 씩 밀려서 저장됩니다.
Complexity: O(n)
근데 만일 insert에서 index가 배열의count라면?
ex)
var arr = [0,1,2] // index == 0,1,2 존재. arr.count = 3
arr.insert(100,3)
이경우에는 append(3)과 같이 삽입됩니다.
var arr = [0,1,2,3]
물론 삽입 과정(insert,append)에서 단일원소가 아닌 연속된 Sequeunce를 삽입 할 수도 있어요.
배열의 삭제는 처음과 끝 그리고 원하는 원소를 삭제 할 수 있습니다.
특정 index의 원소를 삭제 할 경우
- Array.remove(at:)
Complexity: O(n)
index == 0 처음 원소를 삭제 할 경우
- Array.removeFirst()
index == 0에서 순차적으로 원소들을 삭제 할 경우
- Array.removeFirst(개수)
마지막 원소를 삭제 할 경우
- Array.removeLast()
- Array.popLast()
두 함수 모두 마지막 원소를 삭제하고 Complexity: O(1) 인데요.
popLast는 배열이 비어있다면(마지막 원소가 없다면) nil을 반환합니다. 그래서 배열이 비어 있을 때도 사용이 가능한 반면
removeLast는 배열이 비어있지 않은 경우에만 사용이 가능합니다.
첫 원소와 끝 원소 확인
Array.first // 옵셔널 타입
Array[0] // 배열 원소 없으면 에러
Array.last // 옵셔널 타입
Array[Array.count - 1] // 배열 원소 없으면 에러
왜 옵셔널 타입인가? 배열의 원소가 없을 때 nli처리되기 때문! nil에 대한 예외처리를 했다면 계속 실행 될 수 있기에...
자주 사용하는 함수(in 코테)
- min() -> Element?
비교가 가능한 배열에서 가장 작은 Element 반환
- max() -> Element?
가장 큰 Element 반환
- map(_:)
map<T>((Element) throws-> T) -> [T]
배열의 Element를 받아서 T타입으로 반환한다.
이때 T타입은 같은 타입일 수도 있고 다른 타입일 수도 있다. 개발자의 목적에 따라 변경 해 줄수 있다는 것이다.
배열의 Element를 원하는 목적의 타입이나 결과로 반환한 값들을 저장한 배열을 반환한다.
원래는 for in 구문이나 forEach구문으로 배열의 모든 원소들에 대해 각 원소를 개별적으로 받아야 하는데 map을 사용하면 클로저로 간단하게 모든 원소를 다룰 수 있기 때문에 사용합니다.
예를들어
let fruits = ["apple","banana","kiwi"]
let fruitsElementCount = fruits.map{$0.count} // [5,6,4]
let sortedFruitsElement = fruits.map{$0.sorted()}
/*
print(soredFruitsElement)
여기서 sorted는 [Character]로 반환 하기 때문
[["a", "e", "l", "p", "p"], ["a", "a", "a", "b", "n", "n"], ["i", "i", "k", "w"]]
// Character는 String으로 바꿀 수 있어요
*/
- reduce(_:_:)
Declaration
func reduce<Result>(_ initialResult: Result, _nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
첫번째 매개변수는 말 그대로 초기의 결과값 입니다. Int타입의 배열에 모든 원소를 더하고 싶을 때 reduce(0,+)를 사용하는데
var sum = 0
배열.forEach{ sum += $0 } 요런 느낌으로
reduce의 첫번째 매개변수에는 초기에 사용될 Result를 삽입하게 된다면, 두번째 매개변수는 이제 Result와 배열의 Element를 받아 원하는 배열의 원소들의 결과를 만들어 낼 수 있습니다.
다시 말해서 배열의 원소들을 한개의 Result로 합칩니다. 배열의 모든 원소 하나 하나 씩 두번째 매개변수에 클로저의 Element로 전달 받아서 더하거나 빼거나 합한다는 느낌 으으으 예제로 보여드리겠습니다.
var list = [100,30,20]
print(list.reduce(0){$0-$1}) // - 150
print(list.reduce(0,{$0-$1})) // - 150
print(list.reduce(0,-)) // - 150 위와 같은 의미
/*
0에다가 - 100한 값을 Result로 반환하고 반환한 Result(-100)에 - 30을 한 값을 Result로 반환(-130)하고 Result에 - 20을 한 값을 Reuslt로 반환하면 -150
*/
print(list.reduce(0,+))
var list2 = [1,2,3,4]
//이걸 1234로 합치고 싶다면?
print(list2.reduce("",{"\($0)\($1)"})) // 1234 문자
요런 느낌으로 사용 할 수 있습니다.
즉 배열의 모든 원소들을 combine하는 것 입니다.
'Swift > Deep dive!!' 카테고리의 다른 글
[Swift] CustomStringConvertible Protocol 파해치기 (2) | 2022.12.30 |
---|---|
[Swift] 클로저 @escaping과 @non-escaping의 생명주기, 개념과 차이 탐구 (2) | 2022.11.13 |
[Swift] 클래스 2단계 초기화와 안전점검 완벽 이해!! (0) | 2022.07.09 |
[Swift] 자동, 지정, 편의 초기화(in class). 연쇄 호출 관계 뿌수기!! (0) | 2022.07.09 |