¿Cómo enumerar una enumeración con tipo de cadena?

enum Suit: String { case spades = "♠" case hearts = "♥" case diamonds = "♦" case clubs = "♣" } 

Por ejemplo, ¿cómo puedo hacer algo como esto?

 for suit in Suit { // do something with suit print(suit.rawValue) } 

Ejemplo resultante:

 ♠ ♥ ♦ ♣ 

Swift 4.2+

Comenzando con Swift 4.2 (con Xcode 10), solo agregue la conformidad del protocolo a CaseIterable para beneficiarse de allCases :

 extension Suit: CaseIterable {} 

Entonces esto imprimirá todos los valores posibles:

 Suit.allCases.forEach { print($0.rawValue) } 

Compatibilidad con versiones anteriores de Swift (3.x y 4.x)

Simplemente imita la implementación de Swift 4.2:

 #if !swift(>=4.2) 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 in var raw = 0 var first: Self? return AnyIterator { let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) } if raw == 0 { first = current } else if current == first { return nil } raw += 1 return current } }) } } #endif 

Esta publicación es relevante aquí https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-swift

Esencialmente, la solución propuesta es

 enum ProductCategory : String { case Washers = "washers", Dryers = "dryers", Toasters = "toasters" static let allValues = [Washers, Dryers, Toasters] } for category in ProductCategory.allValues{ //Do something } 

Hice una función de utilidad iterateEnum() para iterar casos para tipos de enum arbitrarios.

Aquí está el uso de ejemplo:

 enum Suit:String { case Spades = "♠" case Hearts = "♥" case Diamonds = "♦" case Clubs = "♣" } for f in iterateEnum(Suit) { println(f.rawValue) } 

productos:

 ♠ ♥ ♦ ♣ 

Pero, esto es solo para fines de depuración o prueba : esto se basa en varios comportamientos de comstackdor de stream indocumentada (Swift1.1). A fin de utilizarlo en su propio riesgo 🙂

Aquí está el código:

 func iterateEnum(_: T.Type) -> GeneratorOf { var cast: (Int -> T)! switch sizeof(T) { case 0: return GeneratorOf(GeneratorOfOne(unsafeBitCast((), T.self))) case 1: cast = { unsafeBitCast(UInt8(truncatingBitPattern: $0), T.self) } case 2: cast = { unsafeBitCast(UInt16(truncatingBitPattern: $0), T.self) } case 4: cast = { unsafeBitCast(UInt32(truncatingBitPattern: $0), T.self) } case 8: cast = { unsafeBitCast(UInt64($0), T.self) } default: fatalError("cannot be here") } var i = 0 return GeneratorOf { let next = cast(i) return next.hashValue == i++ ? next : nil } } 

La idea subyacente es:

  • La representación de memoria de enum , excluyendo enum con tipos asociados, es solo un índice de casos, cuando el recuento de casos es 2...256 , es idéntico a UInt8 , cuando 257...65536 , es UInt16 y así sucesivamente. Por lo tanto, puede ser unsafeBitcast de los tipos de entero sin signo correspondientes.
  • .hashValue of enum values ​​es el mismo que el índice del caso.
  • .hashValue of enum values ​​bitcasted from invalid index is 0

ADICIONAL:

Revisado para Swift2 e implementado ideas de casting de la respuesta de @ Kametrixom

 func iterateEnum(_: T.Type) -> AnyGenerator { var i = 0 return anyGenerator { let next = withUnsafePointer(&i) { UnsafePointer($0).memory } return next.hashValue == i++ ? next : nil } } 

AGREGADO: Revisado para Swift3

 func iterateEnum(_: T.Type) -> AnyIterator { var i = 0 return AnyIterator { let next = withUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } } if next.hashValue != i { return nil } i += 1 return next } } 

AGREGADO: Revisado para Swift3.0.1

 func iterateEnum(_: T.Type) -> AnyIterator { var i = 0 return AnyIterator { let next = withUnsafeBytes(of: &i) { $0.load(as: T.self) } if next.hashValue != i { return nil } i += 1 return next } } 

Las otras soluciones funcionan, pero todas hacen suposiciones de, por ejemplo, la cantidad de rangos y palos posibles, o cuál puede ser el primer y el último rango. Es cierto que el diseño de una baraja de cartas probablemente no cambie mucho en el futuro previsible. En general, sin embargo, es mejor escribir un código que haga la menor cantidad posible de suposiciones. Mi solución:

Agregué un tipo sin procesar al enum del traje, así que puedo usar Suit (rawValue 🙂 para acceder a los casos de Suit:

 enum Suit: Int { case Spades = 1 case Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } func color() -> String { switch self { case .Spades: return "black" case .Clubs: return "black" case .Diamonds: return "red" case .Hearts: return "red" } } } enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.rawValue) } } } 

Debajo de la implementación del método createDeck () de Card. init (rawValue 🙂 es un inicializador failable y devuelve un opcional. Al desempaquetar y verificar su valor en ambas declaraciones while, no hay necesidad de suponer el número de casos de Rango o Traje:

 struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } func createDeck() -> [Card] { var n = 1 var deck = [Card]() while let rank = Rank(rawValue: n) { var m = 1 while let suit = Suit(rawValue: m) { deck.append(Card(rank: rank, suit: suit)) m += 1 } n += 1 } return deck } } 

A continuación, se indica cómo llamar al método createDeck:

 let card = Card(rank: Rank.Ace, suit: Suit.Clubs) let deck = card.createDeck() 

La segunda respuesta que realmente funciona

Así que tropecé con los bits y bytes y creé una extensión (que más tarde descubrí que funciona muy similar a la respuesta de @rintaro ). Se puede usar así:

 enum E : EnumCollection { case A, B, C } Array(E.cases()) // [A, B, C] 

Notable es que se puede usar en cualquier enumeración (sin valores asociados). Tenga en cuenta que esto no funciona para enumeraciones que no tienen ningún caso.

Renuncia

Al igual que con la respuesta de @rintaro , este código usa la representación subyacente de una enumeración. Esta representación no está documentada y podría cambiar en el futuro, lo que la rompería -> No recomiendo el uso de esto en la producción.

EDITAR: Ha pasado aproximadamente un año y esto todavía funciona.

Código (Swift 2.2, Xcode 7.3.1)

 protocol EnumCollection : Hashable {} extension EnumCollection { static func cases() -> AnySequence { typealias S = Self return AnySequence { () -> AnyGenerator in var raw = 0 return AnyGenerator { let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory } guard current.hashValue == raw else { return nil } raw += 1 return current } } } } 

Código (Swift 3, Xcode 8.1)

 protocol EnumCollection : Hashable {} extension EnumCollection { static func cases() -> AnySequence { typealias S = Self return AnySequence { () -> AnyIterator in var raw = 0 return AnyIterator { let current : Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee } } guard current.hashValue == raw else { return nil } raw += 1 return current } } } } 

(No tengo idea de por qué necesito las typealias , pero el comstackdor se queja sin él)

(Hice una gran modificación a esta respuesta, mire las ediciones de versiones pasadas)

Puede iterar a través de una enumeración implementando el protocolo ForwardIndexType .

El protocolo ForwardIndexType requiere que defina una función successor() para recorrer los elementos.

 enum Rank: Int, ForwardIndexType { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King // ... other functions // Option 1 - Figure it out by hand func successor() -> Rank { switch self { case .Ace: return .Two case .Two: return .Three // ... etc. default: return .King } } // Option 2 - Define an operator! func successor() -> Rank { return self + 1 } } // NOTE: The operator is defined OUTSIDE the class func + (left: Rank, right: Int) -> Rank { // I'm using to/from raw here, but again, you can use a case statement // or whatever else you can think of return left == .King ? .King : Rank(rawValue: left.rawValue + right)! } 

Al iterar sobre un rango abierto o cerrado ( ..< o ... ) se llamará internamente a la función successor() que le permite escribir esto:

 // Under the covers, successor(Rank.King) and successor(Rank.Ace) are called to establish limits for r in Rank.Ace...Rank.King { // Do something useful } 

En principio, es posible hacerlo de esta manera, suponiendo que no utilice la asignación de valores brutos para los casos de enum:

 enum RankEnum: Int { case Ace case One case Two } class RankEnumGenerator : Generator { var i = 0 typealias Element = RankEnum func next() -> Element? { let r = RankEnum.fromRaw(i) i += 1 return r } } extension RankEnum { static func enumerate() -> SequenceOf { return SequenceOf({ RankEnumGenerator() }) } } for r in RankEnum.enumerate() { println("\(r.toRaw())") } 

Actualizado a Swift 2.2 +

 func iterateEnum(_: T.Type) -> AnyGenerator { var i = 0 return AnyGenerator { let next = withUnsafePointer(&i) { UnsafePointer($0).memory } if next.hashValue == i { i += 1 return next } else { return nil } } } 

es un código actualizado para Swift 2.2 form @ Kametrixom’s swer

Para Swift 3.0+ (muchas gracias a @Philip )

 func iterateEnum(_: T.Type) -> AnyIterator { var i = 0 return AnyIterator { let next = withUnsafePointer(&i) { UnsafePointer($0).pointee } if next.hashValue == i { i += 1 return next } else { return nil } } } 

Si le da a la enumeración un valor Int sin procesar , hará que el bucle sea mucho más fácil.

Por ejemplo, puede usar cualquier anyGenerator para obtener un generador que pueda enumerar sus valores:

 enum Suit: Int, CustomStringConvertible { case Spades, Hearts, Diamonds, Clubs var description: String { switch self { case .Spades: return "Spades" case .Hearts: return "Hearts" case .Diamonds: return "Diamonds" case .Clubs: return "Clubs" } } static func enumerate() -> AnyGenerator { var nextIndex = Spades.rawValue return anyGenerator { Suit(rawValue: nextIndex++) } } } // You can now use it like this: for suit in Suit.enumerate() { suit.description } // or like this: let allSuits: [Suit] = Array(Suit.enumerate()) 

Sin embargo, esto parece un patrón bastante común, ¿no sería bueno si pudiéramos enumerar cualquier tipo de enumerando simplemente por conformarnos a un protocolo? Bueno, con Swift 2.0 y las extensiones de protocolo, ¡ahora podemos!

Simplemente agregue esto a su proyecto:

 protocol EnumerableEnum { init?(rawValue: Int) static func firstValue() -> Int } extension EnumerableEnum { static func enumerate() -> AnyGenerator { var nextIndex = firstRawValue() return anyGenerator { Self(rawValue: nextIndex++) } } static func firstRawValue() -> Int { return 0 } } 

Ahora, cada vez que creas una enumeración (siempre que tenga un valor sin formato Int), puedes hacer que sea enumerable conforme al protocolo:

 enum Rank: Int, EnumerableEnum { case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King } // ... for rank in Rank.enumerate() { ... } 

Si sus valores enum no comienzan con 0 (valor predeterminado), anule el firstRawValue método firstRawValue :

 enum DeckColor: Int, EnumerableEnum { case Red = 10, Blue, Black static func firstRawValue() -> Int { return Red.rawValue } } // ... let colors = Array(DeckColor.enumerate()) 

La última clase de Suit, que incluye el reemplazo de simpleDescription con el protocolo CustomStringConvertible más estándar , se verá así:

 enum Suit: Int, CustomStringConvertible, EnumerableEnum { case Spades, Hearts, Diamonds, Clubs var description: String { switch self { case .Spades: return "Spades" case .Hearts: return "Hearts" case .Diamonds: return "Diamonds" case .Clubs: return "Clubs" } } } // ... for suit in Suit.enumerate() { print(suit.description) } 

EDITAR:

Sintaxis de Swift 3 :

 protocol EnumerableEnum { init?(rawValue: Int) static func firstRawValue() -> Int } extension EnumerableEnum { static func enumerate() -> AnyIterator { var nextIndex = firstRawValue() let iterator: AnyIterator = AnyIterator { defer { nextIndex = nextIndex + 1 } return Self(rawValue: nextIndex) } return iterator } static func firstRawValue() -> Int { return 0 } } 

Me gusta esta solución que reuní después de encontrar esta página: Lista de comprensión en Swift

Utiliza raws Int en lugar de cadenas pero evita escribir dos veces, permite personalizar los rangos y no codifica los valores sin formato.

 enum Suit: Int { case None case Spade, Heart, Diamond, Club static let allRawValues = Suit.Spade.rawValue...Suit.Club.rawValue static let allCases = Array(allRawValues.map{ Suit(rawValue: $0)! }) } enum Rank: Int { case Joker case Two, Three, Four, Five, Six case Seven, Eight, Nine, Ten case Jack, Queen, King, Ace static let allRawValues = Rank.Two.rawValue...Rank.Ace.rawValue static let allCases = Array(allRawValues.map{ Rank(rawValue: $0)! }) } func makeDeck(withJoker withJoker: Bool) -> [Card] { var deck = [Card]() for suit in Suit.allCases { for rank in Rank.allCases { deck.append(Card(suit: suit, rank: rank)) } } if withJoker { deck.append(Card(suit: .None, rank: .Joker)) } return deck } 

Me encontré haciendo .allValues mucho en todo mi código. Finalmente descubrí una manera de simplemente conformarme a un protocolo Iteratable y tener un método rawValues() .

 protocol Iteratable {} extension RawRepresentable where Self: RawRepresentable { static func iterateEnum(_: T.Type) -> AnyIterator { var i = 0 return AnyIterator { let next = withUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } } if next.hashValue != i { return nil } i += 1 return next } } } extension Iteratable where Self: RawRepresentable, Self: Hashable { static func hashValues() -> AnyIterator { return iterateEnum(self) } static func rawValues() -> [Self.RawValue] { return hashValues().map({$0.rawValue}) } } // Example enum Grocery: String, Iteratable { case Kroger = "kroger" case HEB = "heb" case Randalls = "randalls" } let groceryHashes = Grocery.hashValues() // AnyIterator let groceryRawValues = Grocery.rawValues() // ["kroger", "heb", "randalls"] 
 enum Rank: Int { ... static let ranks = (Rank.Ace.rawValue ... Rank.King.rawValue).map{Rank(rawValue: $0)! } } enum Suit { ... static let suits = [Spades, Hearts, Diamonds, Clubs] } struct Card { ... static func fullDesk() -> [Card] { var desk: [Card] = [] for suit in Suit.suits { for rank in Rank.ranks { desk.append(Card(rank: rank,suit: suit)) } } return desk } } 

¿Qué tal esto?

EDITAR: Swift Evolution Proposal SE-0194 La colección derivada de Enum Cases propone una solución de nivel para este problema. Lo vemos en Swift 4.2 y más nuevo. La propuesta también señala algunas soluciones similares a algunas ya mencionadas aquí, pero podría ser interesante de todos modos.

También mantendré mi publicación original por completo.


Este es otro enfoque basado en la respuesta de @ Peymmankh, adaptado a Swift 3 .

 public protocol EnumCollection : Hashable {} extension EnumCollection { public static func allValues() -> [Self] { typealias S = Self let retVal = AnySequence { () -> AnyIterator in var raw = 0 return AnyIterator { let current = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee } } guard current.hashValue == raw else { return nil } raw += 1 return current } } return [S](retVal) } } 

Lo siento, mi respuesta fue específica de cómo utilicé esta publicación en lo que tenía que hacer. Para aquellos que tropiezan con esta pregunta, buscando una manera de encontrar un caso dentro de una enumeración, esta es la manera de hacerlo (nuevo en Swift 2):

Editar: CamelCase en minúsculas ahora es el estándar para los valores enum de Swift 3

 // From apple docs: If the raw-value type is specified as String and you don't assign values to the cases explicitly, each unassigned case is implicitly assigned a string with the same text as the name of that case. enum Theme: String { case white, blue, green, lavender, grey } func loadTheme(theme: String) { // this checks the string against the raw value of each enum case (note that the check could result in a nil value, since it's an optional, which is why we introduce the if/let block if let testTheme = Theme(rawValue: theme) { // testTheme is guaranteed to have an enum value at this point self.someOtherFunction(testTheme) } } 

Para aquellos que se preguntan acerca de la enumeración en una enumeración, las respuestas dadas en esta página que incluyen una var / let estática que contiene una matriz de todos los valores enum son correctas. El último código de ejemplo de Apple para tvOS contiene esta misma técnica.

Dicho esto, deberían construir un mecanismo más conveniente en el lenguaje (Apple, ¿estás escuchando?)!

En Swift 3, cuando la enumeración subyacente tiene {rawValue} s, puede implementar el protocolo {Strideable}. Las ventajas son que no se crean matrices de valores como en otras sugerencias, y que la sentencia estándar Swift “for i in …” funciona, lo que hace que la syntax sea agradable.

 // "Int" to get rawValue, and {Strideable} so we can iterate enum MyColorEnum : Int, Strideable { case Red case Green case Blue case Black //-------- required by {Strideable} typealias Stride = Int func advanced(by n:Stride) -> MyColorEnum { var next = self.rawValue + n if next > MyColorEnum.Black.rawValue { next = MyColorEnum.Black.rawValue } return MyColorEnum(rawValue: next)! } func distance(to other: MyColorEnum) -> Int { return other.rawValue - self.rawValue } //-------- just for printing func simpleDescription() -> String { switch self { case .Red: return "Red" case .Green: return "Green" case .Blue: return "Blue" case .Black: return "Black" } } } // this is how you use it: for i in MyColorEnum.Red ... MyColorEnum.Black { print("ENUM: \(i)") } 

Puedes intentar enumerar de esta manera

 enum Planet: String { case Mercury case Venus case Earth case Mars static var enumerate: [Planet] { var a: [Planet] = [] switch Planet.Mercury { case .Mercury: a.append(.Mercury); fallthrough case .Venus: a.append(.Venus); fallthrough case .Earth: a.append(.Earth); fallthrough case .Mars: a.append(.Mars) } return a } } Planet.enumerate // [Mercury, Venus, Earth, Mars] 

Esto es a lo que terminé yendo; Creo que alcanza el equilibrio correcto de legibilidad y mantenimiento.

 struct Card { // ... static func deck() -> Card[] { var deck = Card[]() for rank in Rank.Ace.toRaw()...Rank.King.toRaw() { for suit in [Suit.Spades, .Hearts, .Clubs, .Diamonds] { let card = Card(rank: Rank.fromRaw(rank)!, suit: suit) deck.append(card) } } return deck } let deck = Card.deck() 

El experimento fue: EXPERIMENTO

Agregue un método a la Tarjeta que crea una baraja completa de cartas, con una carta de cada combinación de rango y palo.

Entonces, sin modificar o mejorar el código dado, aparte de agregar el método (y sin usar cosas que aún no se han enseñado), se me ocurrió esta solución:

 struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } func createDeck() -> [Card] { var deck: [Card] = [] for rank in Rank.Ace.rawValue...Rank.King.rawValue { for suit in Suit.Spades.rawValue...Suit.Clubs.rawValue { let card = Card(rank: Rank(rawValue: rank)!, suit: Suit(rawValue: suit)!) //println(card.simpleDescription()) deck += [card] } } return deck } } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription() let deck = threeOfSpades.createDeck() 

Al igual que con la respuesta de @Kametrixom aquí , creo que devolver una matriz sería mejor que devolver AnySequence, ya que puedes tener acceso a todas las ventajas de Array, como el recuento, etc.

Aquí está la re-escritura:

 public protocol EnumCollection : Hashable {} extension EnumCollection { public static func allValues() -> [Self] { typealias S = Self let retVal = AnySequence { () -> AnyGenerator in var raw = 0 return AnyGenerator { let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory } guard current.hashValue == raw else { return nil } raw += 1 return current } } return [S](retVal) } } 

Enums have toRaw() and fromRaw() methods so if your raw value is an Int, you can iterate from the first to last enum:

 enum Suit: Int { case Spades = 1 case Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } } for i in Suit.Spades.toRaw()...Suit.Clubs.toRaw() { if let covertedSuit = Suit.fromRaw(i) { let description = covertedSuit.simpleDescription() } } 

One gotcha is that you need to test for optional values before running the simpleDescription method, so we set convertedSuit to our value first and then set a constant to convertedSuit.simpleDescription()

This seems like a hack but if you use raw values you can do something like this

 enum Suit: Int { case Spades = 0, Hearts, Diamonds, Clubs ... } var suitIndex = 0 while var suit = Suit.fromRaw(suitIndex++) { ... } 

Here’s my suggested approach. It’s not completely satisfactory (I’m very new to Swift and OOP!) but maybe someone can refine it. The idea is to have each enum provide its own range information as .first and .last properties. It adds just two lines of code to each enum: still a bit hard-coded, but at least it’s not duplicating the whole set. It does require modifying the Suit enum to be an Int like the Rank enum is, instead of untyped.

Rather than echo the whole solution, here’s the code I added to the Rank enum, somewhere after the case statements (Suit enum is similar):

 var first: Int { return Ace.toRaw() } var last: Int { return King.toRaw() } 

and the loop I used to build the deck as an array of String. (The problem definition did not state how the deck was to be structured.)

 func createDeck() -> [String] { var deck: [String] = [] var card: String for r in Rank.Ace.first...Rank.Ace.last { for s in Suit.Hearts.first...Suit.Hearts.last { card = Rank.simpleDescription( Rank.fromRaw(r)!)() + " of " + Suit.simpleDescription( Suit.fromRaw(s)!)() deck.append( card) } } return deck } 

It’s unsatisfactory because the properties are associated to an element rather than to the enum. But it does add clarity to the ‘for’ loops. I’d like it to say Rank.first instead of Rank.Ace.first. It works (with any element), but it’s ugly. Can someone show how to elevate that to the enum level?

And to make it work, I lifted the createDeck method out of the Card struct… could not figure out how to get a [String] array returned from that struct, and that seems a bad place to put such a method anyway.

I did it using computed property, which returns the array of all values (thanks to this post http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ ). However it also uses int raw-values, but I don’t need to repeat all members of enumeration in separate property.

UPDATE Xcode 6.1 changed a bit a way how to get enum member using raw value, so I fixed listing. Also fixed small error with wrong first raw value

 enum ValidSuits:Int{ case Clubs=0, Spades, Hearts, Diamonds func description()->String{ switch self{ case .Clubs: return "♣︎" case .Spades: return "♠︎" case .Diamonds: return "♦︎" case .Hearts: return "♥︎" } } static var allSuits:[ValidSuits]{ return Array( SequenceOf { () -> GeneratorOf in var i=0 return GeneratorOf{ return ValidSuits(rawValue: i++) } } ) } } 

While dealing with Swift 2.0 here is my suggestion:

I have added the raw type to Suit enum

 enum Suit: Int { 

entonces:

 struct Card { var rank: Rank var suit: Suit func fullDeck()-> [Card] { var deck = [Card]() for i in Rank.Ace.rawValue...Rank.King.rawValue { for j in Suit.Spades.rawValue...Suit.Clubs.rawValue { deck.append(Card(rank:Rank(rawValue: i)! , suit: Suit(rawValue: j)!)) } } return deck } } 

For enum representing Int

 enum Filter: Int { case salary case experience case technology case unutilized case unutilizedHV static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case static let allValues = allRawValues.map { Filter(rawValue: $0)!.rawValue } } 

Llámalo así:

 print(Filter.allValues) 

Huellas dactilares:

[0, 1, 2, 3, 4]


For enum representing String

 enum Filter: Int { case salary case experience case technology case unutilized case unutilizedHV static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case static let allValues = allRawValues.map { Filter(rawValue: $0)!.description } } extension Filter: CustomStringConvertible { var description: String { switch self { case .salary: return "Salary" case .experience: return "Experience" case .technology: return "Technology" case .unutilized: return "Unutilized" case .unutilizedHV: return "Unutilized High Value" } } } 

Call it

 print(Filter.allValues) 

Huellas dactilares:

[“Salary”, “Experience”, “Technology”, “Unutilized”, “Unutilized High Value”]

Otra solución:

 enum Suit: String { case spades = "♠" case hearts = "♥" case diamonds = "♦" case clubs = "♣" static var count: Int { return 4 } init(index: Int) { switch index { case 0: self = .spades case 1: self = .hearts case 2: self = .diamonds default: self = .clubs } } } for i in 0.. 

This is a pretty old post, from Swift 2.0. There are now some better solutions here that use newer features of swift 3.0: Iterating through an Enum in Swift 3.0

And on this question there is a solution that uses a new feature of (the not-yet-released as I write this edit) Swift 4.2: How do I get the count of a Swift enum?


There are lots of good solutions in this thread and others however some of them are very complicated. I like to simplify as much as possible. Here is a solution which may or may not work for different needs but I think it works well in most cases:

 enum Number: String { case One case Two case Three case Four case EndIndex func nextCase () -> Number { switch self { case .One: return .Two case .Two: return .Three case .Three: return .Four case .Four: return .EndIndex /* Add all additional cases above */ case .EndIndex: return .EndIndex } } static var allValues: [String] { var array: [String] = Array() var number = Number.One while number != Number.EndIndex { array.append(number.rawValue) number = number.nextCase() } return array } } 

To iterate:

 for item in Number.allValues { print("number is: \(item)") } 

Here a method I use to both iterate an enum, and provide multiple values types from one enum

 enum IterateEnum: Int { case Zero case One case Two case Three case Four case Five case Six case Seven //tuple allows multiple values to be derived from the enum case, and //since it is using a switch with no default, if a new case is added, //a compiler error will be returned if it doesn't have a value tuple set var value: (french:String, spanish:String, japanese:String) { switch self { case .Zero: return (french:"zéro", spanish:"cero", japanese:"nuru") case .One: return (french:"un", spanish:"uno", japanese:"ichi") case .Two: return (french:"deux", spanish:"dos", japanese:"ni") case .Three: return (french:"trois", spanish:"tres", japanese:"san") case .Four: return (french:"quatre", spanish:"cuatro", japanese:"shi") case .Five: return (french:"cinq", spanish:"cinco", japanese:"go") case .Six: return (french:"six", spanish:"seis", japanese:"roku") case .Seven: return (french:"sept", spanish:"siete", japanese:"shichi") } } //Used to iterate enum or otherwise access enum case by index order. //Iterate by looping until it returns nil static func item(index:Int) -> IterateEnum? { return IterateEnum.init(rawValue: index) } static func numberFromSpanish(number:String) -> IterateEnum? { return findItem { $0.value.spanish == number } } //use block to test value property to retrieve the enum case static func findItem(predicate:((_:IterateEnum)->Bool)) -> IterateEnum? { var enumIndex:Int = -1 var enumCase:IterateEnum? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = IterateEnum.item(index: enumIndex) if let eCase = enumCase { if predicate(eCase) { return eCase } } } while enumCase != nil return nil } } var enumIndex:Int = -1 var enumCase:IterateEnum? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = IterateEnum.item(index: enumIndex) if let eCase = enumCase { print("The number \(eCase) in french: \(eCase.value.french), spanish: \(eCase.value.spanish), japanese: \(eCase.value.japanese)") } } while enumCase != nil print("Total of \(enumIndex) cases") let number = IterateEnum.numberFromSpanish(number: "siete") print("siete in japanese: \((number?.value.japanese ?? "Unknown"))") 

Este es el resultado:

The number Zero in french: zéro, spanish: cero, japanese: nuru
The number One in french: un, spanish: uno, japanese: ichi
The number Two in french: deux, spanish: dos, japanese: ni
The number Three in french: trois, spanish: tres, japanese: san
The number Four in french: quatre, spanish: cuatro, japanese: shi
The number Five in french: cinq, spanish: cinco, japanese: go
The number Six in french: six, spanish: seis, japanese: roku
The number Seven in french: sept, spanish: siete, japanese: shichi

Total of 8 cases

siete in japanese: shichi


ACTUALIZAR

I recently created a protocol to handle the enumeration. The protocol requires an enum with an Int raw value:

 protocol EnumIteration { //Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil static func item(index:Int) -> Self? static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) { static func findItem(predicate:((enumCase:Self)->Bool)) -> Self? static func count() -> Int } extension EnumIteration where Self: RawRepresentable, Self.RawValue == Int { //Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil static func item(index:Int) -> Self? { return Self.init(rawValue: index) } static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) { var enumIndex:Int = -1 var enumCase:Self? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = Self.item(enumIndex) if let eCase = enumCase { item(index: enumIndex, enumCase: eCase) } } while enumCase != nil completion?() } static func findItem(predicate:((enumCase:Self)->Bool)) -> Self? { var enumIndex:Int = -1 var enumCase:Self? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = Self.item(enumIndex) if let eCase = enumCase { if predicate(enumCase:eCase) { return eCase } } } while enumCase != nil return nil } static func count() -> Int { var enumIndex:Int = -1 var enumCase:Self? //Iterate until item returns nil repeat { enumIndex += 1 enumCase = Self.item(enumIndex) } while enumCase != nil //last enumIndex (when enumCase == nil) is equal to the enum count return enumIndex } } 

I have used the below method, the assumption is that I know which is the last value in the Rank enum and all the ranks have incremental values after Ace

I prefer this way as it is clean and small, easy to understand

  func cardDeck() -> Card[] { var cards: Card[] = [] let minRank = Rank.Ace.toRaw() let maxRank = Rank.King.toRaw() for rank in minRank...maxRank { if var convertedRank: Rank = Rank.fromRaw(rank) { cards.append(Card(rank: convertedRank, suite: Suite.Clubs)) cards.append(Card(rank: convertedRank, suite: Suite.Diamonds)) cards.append(Card(rank: convertedRank, suite: Suite.Hearts)) cards.append(Card(rank: convertedRank, suite: Suite.Spades)) } } return cards } 

There is a clever way, and frustrating as it is it illustrates the difference between the two different kinds of enums.

Prueba esto:

  func makeDeck() -> Card[] { var deck: Card[] = [] var suits: Suit[] = [.Hearts, .Diamonds, .Clubs, .Spades] for i in 1...13 { for suit in suits { deck += Card(rank: Rank.fromRaw(i)!, suit: suit) } } return deck } 

The deal is that an enum backed by numbers (raw values) is implicitly explicitly ordered, whereas an enum that isn’t backed by numbers is explicitly implicitly unordered.

Eg when we give the enum values numbers, the language is cunning enough to figure out what order the numbers are in. If on the other hand we don’t give it any ordering, when we try to iterate over the values the language throws its hands up in the air and goes “yes, but which one do you want to go first???”

Other languages which can do this (iterating over unordered enums) might be the same languages where everything is ‘under the hood’ actually a map or dictionary, and you can iterate over the keys of a map, whether there’s any logical ordering or not.

So the trick is to provide it with something that is explicitly ordered, in this case instances of the suits in an array in the order we want. As soon as you give it that, Swift is like “well why didn’t you say so in the first place?”

The other shorthand trick is to use the forcing operator on the fromRaw function. This illustrates another ‘gotcha’ about enums, that the range of possible values to pass in is often larger than the range of enums. For instance if we said Rank.fromRaw(60) there wouldn’t be a value returned, so we’re using the optional feature of the language, and where we start using optionals, forcing will soon follow. (Or alternately the if let construction which still seems a bit weird to me)