문제 링크 / Github 링크 |
---|
import Foundation
func solution(_ friends:[String], _ gifts:[String]) -> Int {
return 0
}
import Foundation
func solution(_ friends: [String], _ gifts: [String]) -> Int {
// 선물지수 딕셔너리
var friendGiftPowers = friends.reduce(into: [String: Int]()) { dict, friend in
dict[friend] = 0
}
// 주고받음 딕셔너리
var friendGifts: [[String]:Int] = [:]
for i in 0..<friends.count {
for j in (i + 1)..<friends.count {
friendGifts[ [friends[i], friends[j]] ] = 0
}
}
// 받을선물 딕셔너리
var friendGiftsComing = friends.reduce(into: [String: Int]()) { dict, friend in
dict[friend] = 0
}
// 가장많이받는 수
var result = 0
// 선물지수 & 주고받음 측정
for gift in gifts {
let giftArray = gift.components(separatedBy: .whitespaces)
for key in friendGiftPowers.keys { // 선물지수 측정
if key == giftArray[0] { friendGiftPowers[key]! += 1 }
if key == giftArray[1] { friendGiftPowers[key]! -= 1 }
}
for key in friendGifts.keys { // 주고받음 측정
if key[0] == giftArray[0] && key[1] == giftArray[1] { friendGifts[key]! += 1 }
if key[0] == giftArray[1] && key[1] == giftArray[0] { friendGifts[key]! -= 1 }
}
}
print(friendGiftPowers)
print(friendGifts)
// 받을선물 측정
for key in friendGifts.keys {
if friendGifts[key] == 0 {
if friendGiftPowers[key[0]]! > friendGiftPowers[key[1]]! {
friendGiftsComing[key[0]]! += 1
} else if friendGiftPowers[key[0]]! < friendGiftPowers[key[1]]! {
friendGiftsComing[key[1]]! += 1
}
} else if friendGifts[key]! > 0 {
friendGiftsComing[key[0]]! += 1
} else if friendGifts[key]! < 0 {
friendGiftsComing[key[1]]! += 1
}
}
print(friendGiftsComing)
// 가장많이받는수 측정
result = friendGiftsComing.values.max()!
return result
}
불필요한 반복 제거 및 간결화
friendGiftPowers
와 friendGifts
를 동시에 순회하며 값을 갱신하는 부분에서 불필요한 반복이 있음.
딕셔너리 접근의 강제 언래핑 제거
friendGiftPowers[key]!
와 같은 강제 언래핑(!
)은 안전하지 않음.
코드의 가독성 향상
가독성을 위해 변수를 좀 더 명확하게 이름짓고, 중복되는 코드를 함수로 추출할 수 있음.
import Foundation
func solution(_ friends: [String], _ gifts: [String]) -> Int {
var friendGiftPowers = Dictionary(uniqueKeysWithValues: friends.map { ($0, 0) })
var friendGifts = Dictionary(uniqueKeysWithValues: combinations(friends, 2).map { ($0, 0) })
var friendGiftsComing = Dictionary(uniqueKeysWithValues: friends.map { ($0, 0) })
// 선물지수와 주고받은 선물 처리
for gift in gifts {
let giftArray = gift.components(separatedBy: .whitespaces)
// guard giftArray.count == 2 else { continue } // 입력 데이터 유효성 체크
let giver = giftArray[0], receiver = giftArray[1]
friendGiftPowers[giver, default: 0] += 1
friendGiftPowers[receiver, default: 0] -= 1
let pair1 = [giver, receiver], pair2 = [receiver, giver]
if let _ = friendGifts[pair1] {
friendGifts[pair1, default: 0] += 1
} else if let _ = friendGifts[pair2] {
friendGifts[pair2, default: 0] -= 1
}
}
// 받을 선물 수 계산
for (pair, value) in friendGifts {
let (friend1, friend2) = (pair[0], pair[1])
if value == 0 {
if friendGiftPowers[friend1, default: 0] > friendGiftPowers[friend2, default: 0] {
friendGiftsComing[friend1, default: 0] += 1
} else if friendGiftPowers[friend1, default: 0] < friendGiftPowers[friend2, default: 0] {
friendGiftsComing[friend2, default: 0] += 1
}
} else if value > 0 {
friendGiftsComing[friend1, default: 0] += 1
} else {
friendGiftsComing[friend2, default: 0] += 1
}
}
// 가장 많이 받는 선물 수 반환
return friendGiftsComing.values.max() ?? 0
}
// 친구 리스트에서 조합을 만드는 재귀함수
func combinations<T>(_ array: [T], _ n: Int) -> [[T]] {
guard array.count >= n else { return [] }
if n == 0 { return [[]] }
guard let first = array.first else { return [] }
let rest = Array(array.dropFirst())
return combinations(rest, n - 1).map { [first] + $0 } + combinations(rest, n)
}
Swift에서는 let
뒤에 여러 개의 변수를 한 줄에 선언할 수 있다. 쉼표(,
)로 구분하여 한 번에 여러 값을 바인딩할 수 있으며, 이는 주로 배열, 튜플 등의 데이터를 해체할 때 유용하다.
let giftArray = ["Alice", "Bob"]
let giver = giftArray[0], receiver = giftArray[1]
// `giftArray[0]`의 값은 `giver`에, `giftArray[1]`의 값은 `receiver`에 할당된다.
print(giver) // Alice
print(receiver) // Bob
let (x, y) = (10, 20)
let a = x, b = y
// `(x, y)` 튜플을 해체하여 각각 `x`와 `y`에 값을 할당한 후, 이를 다시 `a`, `b`에 할당한다.
print(a) // 10
print(b) // 20
if let
또는 guard let
에서도 동일한 방식으로 여러 변수를 한 번에 선언할 수 있다.
let optional1: Int? = 5
let optional2: Int? = 10
if let value1 = optional1, let value2 = optional2 {
// `optional1`과 `optional2`가 모두 `nil`이 아니면 두 값을 한 번에 언래핑한다.
print("Both values are unwrapped: \(value1), \(value2)")
}
var
와 let
혼용 불가:let
이거나 모두 var
이어야 한다.let x = 5, y = 10 // OK
var a = 5, b = 10 // OK
let x = 5, var y = 10 // Error!
딕셔너리는 키와 값의 쌍으로 이루어진 데이터 구조이다.
var dictionary: [String: Int] = ["apple": 3, "banana": 5]
String
은 키의 타입Int
는 값의 타입딕셔너리에서 값을 가져오거나 설정할 때, 키가 존재하지 않을 수 있기 때문에 옵셔널 값이 반환된다.
let value = dictionary["apple"] // Optional(3)
let nonExistentValue = dictionary["orange"] // nil
nil
이 반환됨Dictionary
의 subscript(_:default:)
를 활용하여 기본값을 제공할 수 있다.
let value = dictionary["orange", default: 0] // 0
"orange"
가 딕셔너리에 없으면 기본값 0
을 반환함딕셔너리의 특정 값을 업데이트하거나 누적할 때도 default
를 사용하면 유용하다.
var wordCount: [String: Int] = [:]
let words = ["apple", "banana", "apple", "orange", "banana", "apple"]
for word in words {
wordCount[word, default: 0] += 1
// 단어가 딕셔너리에 없으면 기본값 0으로 시작.
// 이미 존재하면 기존 값에 1을 추가.
}
print(wordCount)
// ["apple": 3, "banana": 2, "orange": 1]
기본값은 딕셔너리 안에 또 다른 컬렉션(배열, 딕셔너리)을 포함할 때도 유용하다.
var friendsGifts: [String: [String]] = [:]
friendsGifts["Alice", default: []].append("Book")
friendsGifts["Bob", default: []].append("Pen")
friendsGifts["Alice", default: []].append("Notebook")
// 키 "Alice"나 "Bob"이 없으면 빈 배열 []로 초기화한 후 값 추가.
print(friendsGifts)
// ["Alice": ["Book", "Notebook"], "Bob": ["Pen"]]
딕셔너리로 간단한 카운팅 문제를 해결할 때 default
는 필수적이다.
let text = "hello"
var charCount: [Character: Int] = [:]
for char in text {
charCount[char, default: 0] += 1
}
print(charCount)
// ["h": 1, "e": 1, "l": 2, "o": 1]
!
)이나 옵셔널 바인딩(if let
, guard let
) 없이 값을 안전하게 다룰 수 있다.Dictionary(uniqueKeysWithValues:)
생성자Swift의 uniqueKeysWithValues
는 배열을 딕셔너리로 변환할 때 사용하는 생성자이다. 주어진 배열의 각 요소를 키-값 쌍으로 변환하여 딕셔너리를 생성한다. 키는 유일해야 하며, 중복된 키가 있을 경우 런타임 에러가 발생한다.
uniqueKeysWithValues
는 Dictionary
의 이니셜라이저 중 하나이다.
Dictionary(uniqueKeysWithValues: sequence)
sequence
: 키-값 쌍을 포함하는 배열 또는 시퀀스.let pairs = [("Alice", 25), ("Bob", 30), ("Charlie", 28)]
let dictionary = Dictionary(uniqueKeysWithValues: pairs)
// `pairs` 배열의 각 튜플에서 첫 번째 요소가 키, 두 번째 요소가 값으로 사용됨
print(dictionary)
// ["Alice": 25, "Bob": 30, "Charlie": 28]
let words = ["apple", "banana", "cherry"]
let wordLengths = Dictionary(uniqueKeysWithValues: words.map { ($0, $0.count) })
// `words` 배열에서 각 문자열을 키로, 문자열의 길이를 값으로 하는 딕셔너리가 생생됨
print(wordLengths)
// ["apple": 5, "banana": 6, "cherry": 6]
uniqueKeysWithValues
는 키가 고유해야 한다는 점에서 이름에 unique
가 포함된다. 만약 중복된 키가 있는 경우, 런타임 에러가 발생한다.
let pairs = [("Alice", 25), ("Bob", 30), ("Alice", 28)]
let dictionary = Dictionary(uniqueKeysWithValues: pairs)
// Fatal error: Duplicate keys ("Alice") found when initializing Dictionary
데이터 변환:
고유한 키-값 매핑:
Dictionary(grouping:by:)
: 값들을 그룹화하여 딕셔너리를 생성할 때 사용.zip
: 두 배열을 키와 값으로 묶어 사용할 때 유용.zip
과 함께 사용let keys = ["Alice", "Bob", "Charlie"]
let values = [25, 30, 28]
let dictionary = Dictionary(uniqueKeysWithValues: zip(keys, values))
print(dictionary)
// ["Alice": 25, "Bob": 30, "Charlie": 28]
Dictionary(grouping:by:)
생성자Dictionary(grouping:by:)
는 컬렉션의 요소를 특정 기준으로 그룹화하여 딕셔너리를 생성하는 이니셜라이저이다. 그룹화된 딕셔너리의 키는 기준 함수(by
)의 결과값이고, 값은 해당 키에 매핑된 요소들의 배열이다.
Dictionary(grouping: sequence, by: keyForValue)
sequence
: 그룹화할 대상 시퀀스 (배열, 문자열 등).keyForValue
: 각 요소에 적용할 그룹화 기준을 제공하는 함수.let words = ["apple", "banana", "cherry", "apricot", "blueberry", "grape"]
let groupedByLength = Dictionary(grouping: words, by: { $0.count })
// 단어의 길이(`$0.count`)를 기준으로 단어들을 그룹화함
print(groupedByLength)
// [5: ["apple", "grape"], 6: ["banana", "cherry"], 7: ["apricot"], 9: ["blueberry"]]
// 키는 단어의 길이, 값은 해당 길이의 단어 배열임
let names = ["Alice", "Bob", "Charlie", "Anna", "Brian", "Catherine"]
let groupedByFirstLetter = Dictionary(grouping: names, by: { $0.first! })
// 이름의 첫 글자(`$0.first!`)를 기준으로 그룹화함
print(groupedByFirstLetter)
// ["A": ["Alice", "Anna"], "B": ["Bob", "Brian"], "C": ["Charlie", "Catherine"]]
// 키는 첫 글자, 값은 해당 글자로 시작하는 이름 배열임
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let groupedByEvenOdd = Dictionary(grouping: numbers, by: { $0 % 2 == 0 ? "Even" : "Odd" })
// 숫자를 짝수와 홀수로 나누어 그룹화함
print(groupedByEvenOdd)
// ["Odd": [1, 3, 5, 7, 9], "Even": [2, 4, 6, 8, 10]]
// 키는 "Even" 또는 "Odd"이며, 값은 해당 그룹의 숫자 배열임
누워서 보다가 집중하다보면 앉아서 읽게 되는 마성의 글이네요