TIL: 튜플 (Tuple)

Royce·2025년 3월 10일

Swift 문법

목록 보기
6/63

튜플 (Tuple)

  • 튜플은 여러 개의 값을 한 묶음으로 만드는 Compound(복합 / 혼합) 타입
  • 특별하게 타입이 정해져 있지 않다
  • 포함될 데이터의 갯수를 마음대로 정의할 수 있다
("Royce", 20, "서울")

// 좌표
(Int, Int)

// 3차원 공간
(Int, Int, Int)
  • 사용하는 이유:
    • 관련 데이터 그룹화: 서로 관련 있는 여러 데이터를 하나로 묶어 관리하면, 코드가 더 깔끔해지고 관련 데이터를 한눈에 보기 쉬워진다
    • 간편한 전달: 함수를 호출할 때 여러 개의 값을 한 번에 반환하거나 전달할 때 유용하다
    • 임시 데이터 저장: 간단하게 여러 값을 임시로 저장하고 사용할 때 좋다
let person = ("Royce", 20)  // 튜플 선언 (이름과 나이를 묶음)

// 튜플 내의 값은 인덱스(0, 1, 2, 3, ...)를 이용해 접근할 수 있다
print("이름: \(person.0)")  // 출력 -> 이름: Royce
print("나이: \(person.1)")   // 출력 -> 나이: 20

Named Tuple

  • 일반 튜플은 여러 값을 순서대로 저장하지만, 인덱스로 값을 접근해야 한다
  • 하지만 Named Tuple은 각 요소에 이름을 부여하여, 해당 이름을 통해 값에 접근할 수 있다
  • Named Tuple을 사용하는 이유:
    • 가독성 향상: 각 요소에 의미 있는 이름을 부여함으로써, 코드 내에서 해당 값이 무엇을 나타내는지 바로 알 수 있다
    • 유지보수 용이: 인덱스 대신 이름으로 값을 참조하기 때문에, 튜플의 순서가 바뀌거나 요소가 추가되더라도 코드의 의도를 명확하게 유지할 수 있다
    • 함수 반환값으로 유용: 여러 값을 한 번에 반환할 때, 각각의 반환값에 이름을 부여하면, 함수를 호출하는 쪽에서 어떤 값이 무엇인지 쉽게 파악할 수 있다
// 일반 튜플 (인덱스로 접근)
let person1 = ("Royce", 20)
print("이름: \(person1.0), 나이: \(person1.1)")

// Named Tuple (이름으로 접근)
let person2 = (name: "Royce", age: 20)
print("이름: \(person2.name), 나이: \(person2.age)")

튜플의 분해(Decomposition)

  • 튜플의 분해는 하나의 튜플에 담긴 값들을 각각의 변수나 상수에 한 번에 할당하는 과정이다
  • 예를 들어, (name: "Royce", age: 20)과 같은 튜플이 있을 때, 이 튜플을 분해하여 nameage라는 별도의 변수에 담을 수 있다
  • 사용하는 이유:
    • 가독성 향상: 튜플의 각 요소에 대해 직접 변수 이름을 부여할 수 있어, 어떤 값이 무엇을 의미하는지 쉽게 알 수 있다
    • 코드의 간결함: 인덱스로 접근할 필요 없이, 각 요소에 이름으로 접근할 수 있으므로 코드가 단순해진다
    • 유지보수 용이: 데이터의 의미가 명확하게 표현되기 때문에, 나중에 코드를 수정하거나 확장할 때 이해하기 쉽다
// 튜플의 데이터 묶음을 하나씩 분해하여 상수나 변수에 저장 가능하다
let (first, second, third) = (1, 2, 3)



let person = ("Royce", 20)

// 튜플 분해를 통해 각각의 값을 name과 age에 할당한다
let (name, age) = person

print("이름: \(name)")  // 출력 -> 이름: Royce
print("나이: \(age)")    // 출력 -> 나이: 25



// 튜플 분해 시, 사용하지 않는 값을 _로 표시하여 무시할 수 있다
let personInfo = ("Royce", 20, "Developer")

let (name, age, _) = personInfo    // 세 번째 값("Developer")은 사용하지 않을 때

print("이름: \(name), 나이: \(age)")



// 타입 애일리어스를 이용하여, 치환해서 사용하는 것도 가능하다
typealias GridPoint = (Int, Int)

튜플의 값 비교 (실제로 사용하는 경우는 흔치 않음)

  • 튜플 값의 비교는 두 개의 튜플에 담긴 값들을 순서대로 하나씩 비교하여(사전식(lexicographical) 비교), 전체 튜플 간의 순서를 결정하는 것을 의미한다
  • Swift에서는 튜플의 모든 요소가 비교 가능한(Comparable) 타입일 경우, 튜플끼리 직접 비교할 수 있다
    • 튜플의 각 요소가 모두 Comparable 프로토콜을 준수해야 한다
    • 즉, 각 요소가 <, <=, >, >=, == 등의 연산자를 사용할 수 있어야 튜플 전체에 대한 비교가 가능하다
  • 튜플 값을 비교하는 이유
    • 정렬 및 순서 결정: 여러 개의 값을 함께 저장한 튜플을 정렬할 때, 튜플 값의 비교를 통해 쉽게 순서를 결정할 수 있다(예: 학생 점수와 이름을 담은 튜플 배열을 점수 순으로 정렬)
    • 코드 간결성: 각각의 요소를 일일이 비교하는 대신, 튜플 전체를 한 번에 비교할 수 있어 코드가 훨씬 간단해진다
    • 가독성 향상: 튜플 자체에 의미 있는 순서가 있다면, 비교 연산자를 통해 그 순서를 바로 파악할 수 있으므로 코드의 의도가 명확해진다
let tuple1 = (1, "apple")
let tuple2 = (1, "banana")

// 튜플의 비교는 첫 번째 요소부터 비교하고, 같으면 두 번째 요소를 비교한다
if tuple1 < tuple2 {
    print("tuple1이 tuple2보다 작습니다.")
} else {
    print("tuple1이 tuple2보다 크거나 같습니다.")
}



var students = [
    (name: "Alice", score: 85),
    (name: "Bob", score: 92),
    (name: "Charlie", score: 85)
]

let sortedStudents = students.sorted {        // score(점수)를 우선 기준으로 정렬하고, 점수가 같으면 name(이름)을 기준으로 정렬한다
    return ($0.score, $0.name) < ($1.score, $1.name)    // 튜플 비교 시, 순서대로 비교하게 된다. 여기서는 (score, name) 순서의 튜플로 비교한다
}

for student in sortedStudents {
    print("\(student.name): \(student.score)")
}

Tuple과 switch 문

튜플의 매칭(Matching)

let iOS = (language: "Swift", version: "5")

if iOS.0 == "Swift" && iOS.1 = "5" {
	print("스위프트 버전 5 입니다.")
}

if iOS == ("Swift", "5") {
	print("스위프트 버전 5 입니다.")
}



// Swift의 switch 문은 튜플 매칭을 지원하기 때문에 코드를 단순한 형태로 표현 가능하다
switch iOS {
case ("Swift", "5"):
	print("스위프트 버전 5 입니다.")
default:
	break
}

튜플의 활용

let coordinate = (x: 3, y: 0)

switch coordinate {
case (0, 0):
    // 튜플의 두 값이 모두 0이면, 즉 원점이면 이 케이스가 실행된다.
    print("좌표가 원점입니다.")
    
case (let x, 0):
    // 두 번째 값이 0인 경우: x축 위에 있는 점을 의미한다.
    // 첫 번째 값을 let x로 분해하여 x축 위치를 사용할 수 있다.
    print("x축 위에 위치합니다. x = \(x)")
    
case (0, let y):
    // 첫 번째 값이 0인 경우: y축 위에 있는 점을 의미한다.
    // 두 번째 값을 let y로 분해하여 y축 위치를 사용할 수 있다.
    print("y축 위에 위치합니다. y = \(y)")
    
case let (x, y) where x == y:
    // 추가 조건(where 절)을 사용하여, x와 y의 값이 같은 경우에만 이 케이스가 실행된다.
    print("x와 y의 값이 같고, x = y 1차 함수의 그래프 위에 있습니다. 좌표 = (\(x), \(y))")

case let (x, y) where x == -y:
    // 추가 조건(where 절)을 사용하여, x와 -y의 값이 같은 경우에만 이 케이스가 실행된다.
    print("x와 y의 값이 같고, x = -y 1차 함수의 그래프 위에 있습니다. 좌표 = (\(x), \(y))")
    
default:
    // 위의 모든 조건에 해당하지 않는 경우를 처리한다.
    print("일반적인 위치입니다. 좌표 = (\(coordinate.x), \(coordinate.y))")
}
profile
iOS 개발자 지망생

0개의 댓글