スイーパー:
のは、私はこのようなモデルを持っているとしましょう:
enum UKCountry : String {
case england, scotland, wales, northernIreland
init?(placeName: String) {
// magic happens here
}
}
struct LocalPopulation {
let place: String
let population: Int
}
init(placeName:)
任意の文字列を取り、それがどこにあるか割り出し。例えばinit(placeName: "London")
与えます.england
。それはどのようにこれは重要ではありません。
私も持っている[LocalPopulation]
私が処理したいです。具体的には、私が取得したいです[UKCountry: [LocalPopulation]]
。私はこれを行うことができます:
let populations: [LocalPopulation] = [...]
let dict = Dictionary(grouping: populations, by: { UKCountry(placeName: $0.place)! })
しかし、中にいないすべての場所は、populations
英国の場所なので、UKCountry.init
戻ってくるnil
と、それがクラッシュしていました。私は結果に英国ではない任意の場所を望んでいないことに注意してください。私ができたfilter
、それは手の前に:
let populations: [LocalPopulation] = [...]
let filteredPopulations = populations.filter { UKCountry(placeName: $0.place) != nil }
let dict = Dictionary(grouping: populations, by: { UKCountry(placeName: $0.place)! })
しかし、手段が動作していることをUKCountry.init
二回。それが実装されている方法に応じて、これは高価である可能性があります。私が考える他の方法は次のとおりです。
let populations: [LocalPopulation] = [...]
var dict = Dictionary(grouping: populations, by: { UKCountry(placeName: $0.place) })
dict[nil] = nil
let result = dict as! [UKCountry: [LocalPopulation]]
しかし、それは...上記のすべての試みでは、より迷惑な何、私が使用している少しも「手続き型」です!
。私は時々知っている!
避けられないですが、私はいつでも私ができることを避けるためにしたいと思います。
どのように私はこのSwiftilyを行うことができますか?
ジェシー:
Dictionary(
grouping: populations.compactMap { population in
UKCountry(placeName: population.place).map { ($0, population) }
}
)
public extension Dictionary {
init<Value, KeyValuePairs: Sequence>(grouping pairs: KeyValuePairs)
where
KeyValuePairs.Element == (key: Key, value: Value),
Self.Value == [Value]
{
self =
Dictionary<Key, [KeyValuePairs.Element]>(grouping: pairs, by: \.key)
.mapValues { $0.map(\.value) }
}
init<Value, KeyValuePairs: Sequence>(grouping pairs: KeyValuePairs)
where
KeyValuePairs.Element == (Key, Value),
Self.Value == [Value]
{
self.init( grouping: pairs.map { (key: $0, value: $1) } )
}
}