Reputation: 1532
Is there any way to copy all the values of an enumeration into a dictionary without polling them in any FOR loop?
For example, from this enumeration:
enum FruitPriority: String {
case PEARS
case ORANGES
case APPLES
}
to call some single function from within the ENUM, something like this:
var fruitPriorityArray: [String : Int] = FruitPriority.someFunction()
and get this result (sorted according to hash value):
["PEARS": 0, "ORANGES": 1, "APPLES": 2]
The preference would be to make only a single call to the ENUM.
Thank you.
Upvotes: 0
Views: 801
Reputation: 27221
enum FruitPriority: String, CaseIterable {
case PEARS
case ORANGES
case APPLES
}
let result = FruitPriority.allCases.enumerated().reduce([String: Int]()) { dict, fruit in
var dict = dict
dict[fruit.element.rawValue] = fruit.offset
return dict
}
print(result)
The result is:
["PEARS": 0, "ORANGES": 1, "APPLES": 2]
For version Swift 4.1 and earlier the implementation of CaseIterable
:
#if swift(>=4.2)
#else
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
})
}
}
#endif
Original post of CaseIterable
implementation.
Upvotes: 2
Reputation: 154631
If you make your enum CaseIterable
, you can construct a dictionary using reduce(into:)
. Since the hashValue
can now change from run to run, I would recommend using enumerated()
to number the cases in order:
enum FruitPriority: String, CaseIterable {
case PEARS
case ORANGES
case APPLES
}
let result = FruitPriority.allCases.enumerated().reduce(into: [:]) { $0[$1.element.rawValue] = $1.offset }
print(result)
// ["ORANGES": 1, "APPLES": 2, "PEARS": 0]
Upvotes: 1
Reputation: 11200
If you need just single call to the enum:
Add CaseIterable
to your enum and then just create function getDictionary
in enum which returns you dictionary (for each enum case will be rawValue
assigned as key
and hashValue
as value
)
enum FruitPriority: String, CaseIterable {
case PEARS
case ORANGES
case APPLES
func getDictionary() -> [String: Int] {
var dictionary = [String: Int]()
FruitPriority.allCases.forEach {
dictionary[$0.rawValue] = $0.hashValue
}
return dictionary
}
}
then you can just call
var fruitPriorityArray: [String : Int] = FruitPriority.getDictionary()
Note: if you're using earlier versions of Swift you can see this to create CaseIterable
protocol
Upvotes: 1