본문 바로가기

Swift/Deep dive!!

[Swift] Array 의미와 선언(Set과의 차이점은?), 자주 사용하는 함수(in 코테)

 

 

 


배열(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하는 것 입니다.