John S
John S

Reputation: 267

Get index of enum with extension of String,

I have an Enum that looks like this:

enum Status: String {
    case online = "online"
    case offline = "offline"
    case na = "na"
}

I need the String value and I know how to get it, but my question is if it´s possible to get the index value too for each case in the enum.

0 for online, 1 for offline and 2 for na.

I will add more statues in the future.

Upvotes: 12

Views: 14501

Answers (6)

Egzon P.
Egzon P.

Reputation: 4778

Great answer of @JMI in Swift 5.

enum MyEnum: CaseIterable {
  case one
  case two
}

extension CaseIterable where Self: Equatable {
    var index: Self.AllCases.Index? {
        return Self.allCases.firstIndex { self == $0 }
    }
}

How to use:

guard let enumCaseIndex = MyEnum.one.index else { return }
print("Enum case index: ", \(enumCaseIndex)) // prints: 0

Upvotes: 10

tontonCD
tontonCD

Reputation: 358

I did use a solution witch is almost the same than santhosh-shettigar:

func toInt() -> Int {
        let allValues: NSArray = MyEnum.allCases as NSArray
        let result: Int = allValues.index(of: self)
        return result
    }

Simple! I use the Swift built-in MyEnum.allCases, ...but I'm not sure that in Swift Specification, we have the guaranty that the Array return by MyEnum.allCases is always in the same order, the one used at the MyEnum definition???

Upvotes: 3

JMI
JMI

Reputation: 2628

-------- UPDATE -------

Since swift 4.2 you can do following:

enum Status: String, CaseIterable {

    case online
    case offline
    case na
}

extension CaseIterable where Self: Equatable {

    var index: Self.AllCases.Index? {
        return Self.allCases.index { self == $0 }
    }
}

or as I wrote earlier:

enum Status: Int {

    case online = 0
    case offline
    case na

    var index: Int {
        return rawValue
    }
    var value: String {
        return String(describing: self)
    }
}

-------- ORIGIN ANSWER -------

I'm using this extension:

protocol EnumIterable: RawRepresentable {

    static var allValues: [Self] { get }
    var index: Int? { get }
}

extension EnumIterable {

    static var count: Int {
        return allValues.count
    }
}

extension EnumIterable where Self.RawValue: Equatable {

    var next: Self? {
        if let index = Self.allValues.index(where: { rawValue == $0.rawValue }) {
            return Self.allValues[safe: index + 1]
        }
        return nil
    }

    var index: Int? {
        return Self.allValues.index { rawValue == $0.rawValue }
    }
}

But you would define allValues variable:

enum Status: String, EnumIterable {

    case online = "online"
    case offline = "offline"
    case na = "na"

    static var allValues: [Status] {
        return [
            .online,
            .offline,
            .na,
        ]
    }
}

Something similar was solved here (count of enumerations): How do I get the count of a Swift enum?

Next possibility is to define enum like this:

enum Status: Int {

    case online = 0
    case offline
    case na

    var index: Int {
        return rawValue
    }
    var value: String {
        return String(describing: self)
    }
}

print (Status.online.value) // online
print (Status.online.index) // 0

or

enum Status: Int {

    case online = 0
    case offline
    case na

    var index: Int {
        return rawValue
    }
    var value: String {
        switch self {
        case .online:
            return "online"
        case .offline:
            return "offline"
        case .na:
            return "na"
        }
    }
}

print (Status.online.value) // online
print (Status.online.index) // 0

Note: for defining string value, you can use CustomStringConvertible protocol.

Eg:

enum Status: Int, CustomStringConvertible {

    case online = 0
    case offline
    case na

    var index: Int {
        return rawValue
    }
    var description: String {
        switch self {
        case .online:
            return "online"
        case .offline:
            return "offline"
        case .na:
            return "na"
        }
    }
}

Upvotes: 17

MGK
MGK

Reputation: 7098

Possible work around may to associate custom functions with enum

enum ToolbarType : String{
        case Case = "Case", View="View", Information="Information"
        static let allValues = [Case, View, Information]

        func ordinal() -> Int{
            return ToolbarType.allValues.index(of: self)!
        }
 }

Can be used as

 for item in ToolbarType.allValues {
        print("\(item.rawValue): \(item.ordinal())")
 }

Output

Case: 0
View: 1
Information: 2

Upvotes: 1

Duyen-Hoa
Duyen-Hoa

Reputation: 15784

As enum in Swift does not have index of its values (please read the post in Martin R's comment), you have to create your self some 'index' function or to map all values to an Array to have the index.

You can implement as in this post or another way to do:

enum Status: String {
    case online = "online"
    case offline = "offline"
    case na = "na"

    static func index(of aStatus: Status) -> Int {
        let elements = [Status.online, Status.offline, Status.na]

        return elements.index(of: aStatus)!
    }

    static func element(at index: Int) -> Status? {
        let elements = [Status.online, Status.offline, Status.na]

        if index >= 0 && index < elements.count {
            return elements[index]
        } else {
            return nil
        }
    }
}

let a = Status.na

//return 2
let index = Status.index(of: a)

//return Status.offline
let element2 = Status.element(at: 1)

//return nil
let element3 = Status.element(at: 3)

Upvotes: 5

Bilal
Bilal

Reputation: 19156

How about this.

enum Status: Int {
    case online = 0
    case offline = 1
    case na = 2
}

You can get the string value and the integer index both.

// enum as string 
let enumName = "\(Status.online)" // `online`

// enum as int value 
let enumValue = Status.online.rawValue // 0

// enum from int
let enumm = Status.init(rawValue: 1)

Hope it helps. Thanks.

Upvotes: 1

Related Questions