사전의 모든 키에 함수를 매핑하고 싶습니다. 다음과 같은 것이 효과가 있기를 희망했지만 필터를 사전에 직접 적용 할 수는 없습니다. 이것을 달성하는 가장 깨끗한 방법은 무엇입니까?
이 예제에서는 각 값을 1 씩 늘리려 고합니다. 그러나이 예제에서는 부수적입니다. 주 목적은 map ()을 사전에 적용하는 방법을 알아내는 것입니다.
var d = ["foo" : 1, "bar" : 2]
d.map() {
$0.1 += 1
}
답변
스위프트 4+
좋은 소식! Swift 4에는 mapValues(_:)
동일한 키는 있지만 값이 다른 사전의 사본을 구성 하는 방법이 포함되어 있습니다. 그것은 또한 포함 filter(_:)
반환 과부하 Dictionary
및 init(uniqueKeysWithValues:)
과 init(_:uniquingKeysWith:)
을 만들 초기화를 Dictionary
튜플 임의의 순서로한다. 즉, 키와 값을 모두 변경하려면 다음과 같이 말할 수 있습니다.
let newDict = Dictionary(uniqueKeysWithValues:
oldDict.map { key, value in (key.uppercased(), value.lowercased()) })
누락 된 요소에 대한 기본값을 대체하고, 값을 그룹화 (컬렉션을 배열의 사전으로 변환, 일부 함수를 통해 콜렉션을 맵핑 한 결과로 키가 지정된) 등으로 사전을 병합하는 새로운 API도 있습니다.
이러한 기능을 소개 한 제안서 SE-0165에 대해 토론 하면서이 스택 오버플로 답변을 여러 번 제기했으며, 많은 수의 업 보트가 수요를 입증하는 데 도움이되었다고 생각합니다. Swift를 개선하는 데 도움을 주셔서 감사합니다.
답변
Swift 5에서는 다음 5 가지 스 니펫 중 하나를 사용 하여 문제를 해결할 수 있습니다.
#1. Dictionary
mapValues(_:)
방법을 사용하여
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.mapValues { value in
return value + 1
}
//let newDictionary = dictionary.mapValues { $0 + 1 } // also works
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
# 2. 사용 Dictionary
map
방법 및 init(uniqueKeysWithValues:)
이니셜 라이저
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let tupleArray = dictionary.map { (key: String, value: Int) in
return (key, value + 1)
}
//let tupleArray = dictionary.map { ($0, $1 + 1) } // also works
let newDictionary = Dictionary(uniqueKeysWithValues: tupleArray)
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
#삼. 사용 Dictionary
reduce(_:_:)
방법 또는 reduce(into:_:)
방법을
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.reduce([:]) { (partialResult: [String: Int], tuple: (key: String, value: Int)) in
var result = partialResult
result[tuple.key] = tuple.value + 1
return result
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
let newDictionary = dictionary.reduce(into: [:]) { (result: inout [String: Int], tuple: (key: String, value: Int)) in
result[tuple.key] = tuple.value + 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
# 4. Dictionary
subscript(_:default:)
아래 첨자 사용
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
var newDictionary = [String: Int]()
for (key, value) in dictionary {
newDictionary[key, default: value] += 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
# 5. Dictionary
subscript(_:)
아래 첨자 사용
let dictionary = ["foo": 1, "bar": 2, "baz": 5]
var newDictionary = [String: Int]()
for (key, value) in dictionary {
newDictionary[key] = value + 1
}
print(newDictionary) // prints: ["baz": 6, "foo": 2, "bar": 3]
답변
여기에있는 대부분의 답변은 전체 사전 (키 와 값) 을 매핑하는 방법에 중점을 두지 만 질문은 실제로 값만 매핑하려고했습니다. 키와 값을 모두 맵핑하면 키가 중복 될 수 있지만 값을 맵핑하면 동일한 수의 항목을 보장 할 수 있으므로 이는 중요한 차이점입니다.
여기 mapValues
에 값만 매핑 할 수 있는 확장 이 있습니다. 또한 init
일련의 키 / 값 쌍을 사용하여 사전을 확장합니다 . 이는 배열에서 사전을 초기화하는 것보다 약간 더 일반적입니다.
extension Dictionary {
init<S: SequenceType where S.Generator.Element == Element>
(_ seq: S) {
self.init()
for (k,v) in seq {
self[k] = v
}
}
func mapValues<T>(transform: Value->T) -> Dictionary<Key,T> {
return Dictionary<Key,T>(zip(self.keys, self.values.map(transform)))
}
}
답변
가장 깨끗한 방법은 map
사전에 추가 하는 것입니다.
extension Dictionary {
mutating func map(transform: (key:KeyType, value:ValueType) -> (newValue:ValueType)) {
for key in self.keys {
var newValue = transform(key: key, value: self[key]!)
self.updateValue(newValue, forKey: key)
}
}
}
작동하는지 확인 :
var dic = ["a": 50, "b": 60, "c": 70]
dic.map { $0.1 + 1 }
println(dic)
dic.map { (key, value) in
if key == "a" {
return value
} else {
return value * 2
}
}
println(dic)
산출:
[c: 71, a: 51, b: 61]
[c: 142, a: 51, b: 122]
답변
reduce
지도 대신 사용할 수도 있습니다 . 더 많은 reduce
일을 map
할 수 있습니다!
let oldDict = ["old1": 1, "old2":2]
let newDict = reduce(oldDict, [String:Int]()) { dict, pair in
var d = dict
d["new\(pair.1)"] = pair.1
return d
}
println(newDict) // ["new1": 1, "new2": 2]
이것을 확장으로 감싸는 것은 상당히 쉽지만 확장명이 없어도 한 번의 함수 호출로 원하는 것을 수행 할 수 있습니다.
답변
당신이 할 수있는 것으로 나타났습니다. 당신이해야 할 일은 MapCollectionView<Dictionary<KeyType, ValueType>, KeyType>
사전 keys
메소드 에서 반환 된 배열을 만드는 것입니다. ( 정보는 여기에 ) 그런 다음이 배열을 매핑 할 수 있습니다, 그리고 다시 사전에 업데이트 된 값을 전달합니다.
var dictionary = ["foo" : 1, "bar" : 2]
Array(dictionary.keys).map() {
dictionary.updateValue(dictionary[$0]! + 1, forKey: $0)
}
dictionary
답변
Swift Standard Library Reference에 따르면 map은 배열의 함수입니다. 사전이 아닙니다.
그러나 사전을 반복하여 키를 수정할 수 있습니다.
var d = ["foo" : 1, "bar" : 2]
for (name, key) in d {
d[name] = d[name]! + 1
}
