0

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.

vacawama
  • 150,663
  • 30
  • 266
  • 294
iSofia
  • 1,412
  • 2
  • 19
  • 36
  • An “associative array” is called *dictionary* in Swift. A dictionary is an *unordered* collection of key/value pairs. – Martin R Dec 01 '18 at 14:06
  • @MartinR Thank you for your prompt answer. You're right. So, would it be possible to accomplish this *unordered?* – iSofia Dec 01 '18 at 14:08
  • Why would you need it like that? Why not just change the raw value to an `Int` and use the raw value instead? – Rakesha Shastri Dec 01 '18 at 14:09

3 Answers3

2
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.

Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
1

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

Robert Dresler
  • 10,580
  • 2
  • 22
  • 40
1

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]
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • Thank you, vacawama, for the tip on ***reduce into.*** I'm trying to implement it as it seems so much simpler. – iSofia Dec 01 '18 at 14:26