it-swarm.com.de

Wie kann man eine Aufzählung mit dem Typ "String" auflisten?

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

Wie kann ich zum Beispiel so etwas tun:

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

Ergebnisbeispiel:

♠
♥
♦
♣
469
Lucien

Swift 4.2+

Beginnen Sie mit Swift 4.2 (mit Xcode 10) und fügen Sie die Protokollkonformität zu CaseIterable hinzu, um von allCases zu profitieren:

extension Suit: CaseIterable {}

Dann werden alle möglichen Werte gedruckt:

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

Kompatibilität mit früheren Swift-Versionen (3.x und 4.x)

Imitieren Sie einfach die Implementierung von 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<Self> 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
172
Cœur

Dieser Beitrag ist relevant hier https://www.Swift-studies.com/blog/2014/6/10/enumerating-enums-in-Swift

Im Wesentlichen ist die vorgeschlagene Lösung

enum ProductCategory : String {
     case Washers = "washers", Dryers = "dryers", Toasters = "toasters"

     static let allValues = [Washers, Dryers, Toasters]
}

for category in ProductCategory.allValues{
     //Do something
}
504
rougeExciter

Ich habe eine Hilfsfunktion iterateEnum() für das Durchlaufen von Fällen für beliebige enum-Typen erstellt.

Hier ist die Beispielnutzung:

enum Suit:String {
    case Spades = "♠"
    case Hearts = "♥"
    case Diamonds = "♦"
    case Clubs = "♣"
}

for f in iterateEnum(Suit) {
    println(f.rawValue)
}

ausgänge:

♠
♥
♦
♣

Dies ist jedoch nur für Debugging oder TestZweck: Dies beruht auf mehreren undokumentierten aktuellen (Swift1.1) Compiler-Verhalten. Also auf eigene Gefahr benutzen :)

Hier ist der Code:

func iterateEnum<T: Hashable>(_: T.Type) -> GeneratorOf<T> {
    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
    }
}

Die Grundidee ist:

  • Die Speicherdarstellung von enum - ausgenommen enums mit zugehörigen Typen - ist nur ein Index von Fällen. Wenn die Anzahl der Fälle 2...256 ist, ist sie identisch mit UInt8. Wenn 257...65536, UInt16 und so weiter. Es kann also unsafeBitcast von entsprechenden vorzeichenlosen Integer-Typen sein.
  • .hashValue der Aufzählungswerte entspricht dem Index des Falls.
  • .hashValue von Aufzählungswerten, die von ungültig übertragen wurden. Index ist 0.

HINZUGEFÜGT:

Für Swift2 überarbeitet und Casting-Ideen aus @ Kametrixoms Antwort umgesetzt

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

ADDED: Überarbeitet für Swift3

func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
    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
    }
}

ADDED: Überarbeitet für Swift3.0.1

func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
    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
    }
}
272
rintaro

Die anderen Lösungen Arbeit aber sie alle setzen Annahmen über die Anzahl der möglichen Ränge und Anzüge oder den ersten und letzten Rang. Sicher, das Layout eines Kartensets wird sich in absehbarer Zeit wahrscheinlich nicht viel ändern. Im Allgemeinen ist es jedoch besser, Code zu schreiben, der so wenig Annahmen wie möglich macht. Meine Lösung:

Ich habe der Suit-Enumance einen Raw-Typ hinzugefügt, sodass ich Suit (rawValue :) verwenden kann, um auf die Suit-Fälle zuzugreifen:

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)
        }
    }
}

Unter der Implementierung der Methode createDeck () von Card. init (rawValue :) ist ein fehlgeschlagener Initialisierer und gibt einen optionalen Wert zurück. Durch das Auspacken und Überprüfen des Werts in beiden Anweisungen während der Anweisung müssen Sie nicht die Anzahl der Rang- oder Anzugfälle annehmen:

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
    }
}

So rufen Sie die createDeck-Methode auf:

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

Die zweite Antwort, die wirklich funktioniert

Also bin ich in den Bits und Bytes herumgestolpert und habe eine Erweiterung erstellt (die später herausfand, dass die Antwort von @rintaro sehr ähnlich ist). Es ist so verwendbar:

enum E : EnumCollection {
    case A, B, C
}

Array(E.cases())    // [A, B, C]

Bemerkenswert ist, dass es für jedes Enum (ohne zugehörige Werte) verwendet werden kann. Beachten Sie, dass dies nicht für Aufzählungen funktioniert, die keine Fälle enthalten.

Haftungsausschluss

Wie bei der Antwort von @rintaro verwendet dieser Code die zugrunde liegende Darstellung einer Aufzählung. Diese Darstellung ist nicht dokumentiert und kann sich in der Zukunft ändern, was sie zerstören könnte -> Ich empfehle die Verwendung dieser Option in der Produktion nicht. 

Code (Swift 2.2, Xcode 7.3.1, funktioniert nicht mit Xcode 10)

protocol EnumCollection : Hashable {}
extension EnumCollection {
    static func cases() -> AnySequence<Self> {
        typealias S = Self
        return AnySequence { () -> AnyGenerator<S> 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
            }
        }
    }
}

Code (Swift 3, Xcode 8.1, funktioniert nicht mit Xcode 10)

protocol EnumCollection : Hashable {}
extension EnumCollection {
    static func cases() -> AnySequence<Self> {
        typealias S = Self
        return AnySequence { () -> AnyIterator<S> 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
            }
        }
    }
}

(Ich habe keine Ahnung, warum ich typealias brauche, aber der Compiler beschwert sich ohne).

(Ich habe große Änderungen an dieser Antwort vorgenommen, siehe die Änderungen für frühere Versionen.)

71
Kametrixom

Sie können eine Enumeration durchlaufen, indem Sie das ForwardIndexType-Protokoll implementieren.

Das ForwardIndexType-Protokoll erfordert, dass Sie eine successor()-Funktion definieren, um die Elemente schrittweise durchzugehen.

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)!
}

Durch Iteration über einen offenen oder geschlossenen Bereich (..< oder ...) wird intern die Funktion successor() aufgerufen, mit der Sie Folgendes schreiben können:

// 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
}
25
RndmTsk

Im Prinzip ist es möglich, auf diese Weise zu tun, vorausgesetzt, dass Sie keine Rohwertzuordnung für Fälle von Enum verwenden:

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<RankEnum> {
    return SequenceOf<RankEnum>({ RankEnumGenerator() })
  }
}

for r in RankEnum.enumerate() {
  println("\(r.toRaw())")
}
17
Alfa07

Wenn Sie die Aufzählung einen rohen Int-Wert angeben, wird das Schleifen wesentlich einfacher.

Beispielsweise können Sie anyGenerator verwenden, um einen Generator zu erhalten, der Ihre Werte auflisten kann:

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<Suit> {
        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())

Dies scheint jedoch ein ziemlich allgemeines Muster zu sein. Wäre es nicht Nizza, wenn wir einen Enummentyp machen könnten, indem wir uns einfach an ein Protokoll halten? Gut mit Swift 2.0 und Protokollerweiterungen, jetzt können wir!

Fügen Sie dies einfach zu Ihrem Projekt hinzu:

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

Jedes Mal, wenn Sie eine Enumeration erstellen (solange es einen Int-Rohwert hat), können Sie es durch Protokollkonformität auflisten.

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

Wenn Ihre Aufzählungswerte nicht mit 0 (Standardeinstellung) beginnen, überschreiben Sie die firstRawValue-Methode:

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

Die letzte Suit-Klasse, einschließlich des Ersetzens von simpleDescription durch das standardisiertes CustomStringConvertible-Protokoll , sieht folgendermaßen aus:

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)
}

EDIT:

Swift 3-Syntax:

protocol EnumerableEnum {
    init?(rawValue: Int)
    static func firstRawValue() -> Int
}

extension EnumerableEnum {
    static func enumerate() -> AnyIterator<Self> {
        var nextIndex = firstRawValue()

        let iterator: AnyIterator<Self> = AnyIterator {
            defer { nextIndex = nextIndex + 1 }
            return Self(rawValue: nextIndex)
        }

        return iterator
    }

    static func firstRawValue() -> Int {
        return 0
    }
}
13
Senseful

Auf Swift 2.2 + aktualisiert

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

der Code wurde in Swift 2.2-Formular @ Kametrixoms an swer aktualisiert

Für Swift 3.0+ (vielen Dank an @Philip )

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

Dieses Problem ist jetzt viel einfacher. Hier ist meine Swift 4.2-Lösung.

enum Suit: Int, CaseIterable {
    case None
    case Spade, Heart, Diamond, Club

    static let allNonNullCases = Suit.allCases[Spade.rawValue...]
}

enum Rank: Int, CaseIterable {
    case Joker
    case Two, Three, Four, Five, Six, Seven, Eight
    case Nine, Ten, Jack, Queen, King, Ace

    static let allNonNullCases = Rank.allCases[Two.rawValue...]
}

func makeDeck(withJoker: Bool = false) -> [Card] {
    var deck = [Card]()
    for suit in Suit.allNonNullCases {
        for rank in Rank.allNonNullCases {
            deck.append(Card(suit: suit, rank: rank))
        }
    }
    if withJoker {
        deck.append(Card(suit: .None, rank: .Joker))
    }
    return deck
}

Pre 4.2

Diese Lösung gefällt mir, nachdem ich diese Seite gefunden habe: Listenverständnis in Swift

Es verwendet Int-Raws anstelle von Strings, vermeidet jedoch zweimaliges Eingeben, ermöglicht das Anpassen der Bereiche und schreibt keine Rohwerte.

Dies ist die Swift 4-Version meiner ursprünglichen Lösung, siehe 4.2 oben.

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: Bool = false) -> [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
}
11
adazacom

Ich habe festgestellt, dass ich in meinem Code .allValues viel machte. Schließlich habe ich einen Weg gefunden, einfach einem Iteratable-Protokoll zu entsprechen und eine rawValues()-Methode zu haben.

protocol Iteratable {}
extension RawRepresentable where Self: RawRepresentable {

    static func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
        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<Self> {
        return iterateEnum(self)
    }

    static func rawValues() -> [Self.RawValue] {
        return hashValues().map({$0.rawValue})
    }
}


// Example
enum Grocery: String, Iteratable {
    case Kroger = "kroger"
    case HEB = "h.e.b."
    case Randalls = "randalls"
}

let groceryHashes = Grocery.hashValues() // AnyIterator<Grocery>
let groceryRawValues = Grocery.rawValues() // ["kroger", "h.e.b.", "randalls"]
7

BEARBEITEN: Vorschlag für eine schnelle EntwicklungSE-0194 Abgeleitete Sammlung von Enum-Fällen schlägt eine Ebene mit Lösung für dieses Problem vor. Wir sehen es in Swift 4.2 und neuer. Der Vorschlag weist auch auf einige Workarounds hin, die denen ähneln, die bereits hier erwähnt wurden, es könnte jedoch interessant sein, dies zu sehen.

Ich werde meinen ursprünglichen Posten auch der Vollständigkeit halber behalten.


Dies ist ein weiterer Ansatz, der auf der Antwort von @ Peymmankh basiert und an Swift 3 angepasst ist.

public protocol EnumCollection : Hashable {}

extension EnumCollection {

public static func allValues() -> [Self] {
    typealias S = Self

    let retVal = AnySequence { () -> AnyIterator<S> 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)
  }
}
6
ff10
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
    }
}

Wie wäre es damit?

5
Mossila

Entschuldigung, meine Antwort war spezifisch, wie ich diesen Beitrag in dem verwendet habe, was ich tun musste. Für diejenigen, die über diese Frage stolpern und nach einem Weg suchen, um einen Fall innerhalb einer Aufzählung zu finden , ist dies der Weg, dies zu tun (neu in Swift 2):

Bearbeiten: CamelCase in Kleinbuchstaben ist jetzt der Standard für Swift 3 Aufzählungswerte

// 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)
        }
    }

Für diejenigen, die sich über die Aufzählung in einer Aufzählung wundern, sind die Antworten auf dieser Seite, die eine statische Variable mit einem Array aller Aufzählungswerte enthalten, korrekt. Der neueste Apple Beispielcode für tvOS enthält genau dieselbe Technik.

Davon abgesehen sollten sie einen bequemeren Mechanismus in die Sprache einbauen (Apple, hören Sie zu?)!

4
Gene Loparco

In Swift 3 können Sie das {Strideable} -Protokoll implementieren, wenn das zugrunde liegende Enum {rawValue} hat. Die Vorteile sind, dass keine Werte-Arrays erstellt werden, wie in einigen anderen Vorschlägen, und dass die standardmäßige Swift-Anweisung "for i in ..." funktioniert, die für die Nice-Syntax sorgt.

// "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)")
}
4
ACK

Sie können versuchen, so aufzuzählen

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]
4
Karthik Kumar

Damit bin ich am Ende gegangen; Ich denke, es ist das richtige Gleichgewicht zwischen Lesbarkeit und Wartbarkeit.

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()
4
Andrew

Xcode 10 mit Swift 4.2

enum Filter: String, CaseIterable {

    case salary = "Salary"
    case experience = "Experience"
    case technology = "Technology"
    case unutilized = "Unutilized"
    case unutilizedHV = "Unutilized High Value"

    static let allValues = Filter.allCases.map { $0.rawValue }
}

Nennen

print(Filter.allValues)

Drucke:

["Gehalt", "Erfahrung", "Technologie", "ungenutzt", "ungenutzter hoher Wert"]


ältere Versionen

Für enum, die Int darstellt

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 }
}

Nenne es so:

print(Filter.allValues)

Drucke:

[0, 1, 2, 3, 4]


Für enum, die String darstellt

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"
        }
    }
}

Nennen

print(Filter.allValues)

Drucke:

["Gehalt", "Erfahrung", "Technologie", "ungenutzt", "ungenutzter hoher Wert"]

3

Das Experiment war: EXPERIMENT

Fügen Sie der Karte eine Methode hinzu, die ein volles Kartendeck mit einer Karte aus jeder Kombination von Rang und Farbe erstellt.

Also, ohne den angegebenen Code zu ändern oder zu verbessern, außer die Methode hinzuzufügen (und ohne etwas zu verwenden, das noch nicht gelehrt wurde), kam ich zu dieser Lösung:

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()
3
Hans-Peter

Beim Umgang mit Swift 2.0 ist hier mein Vorschlag:

Ich habe den Rohtyp zu Suitenum hinzugefügt. 

enum Suit: Int {

dann:

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
    }
}
2
Aladin

Wie bei @Kametrixom answer here Ich glaube, ein Array zurückzugeben wäre besser als AnySequence, da man auf alle Goodies von Array wie count zugreifen kann.

Hier ist das Umschreiben:

public protocol EnumCollection : Hashable {}
extension EnumCollection {
    public static func allValues() -> [Self] {
        typealias S = Self
        let retVal = AnySequence { () -> AnyGenerator<S> 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)
    }
}
2
Peymankh

Ich habe es mit einer berechneten Eigenschaft gemacht, die das Array aller Werte zurückgibt (dank diesem Beitrag http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ ). Es verwendet jedoch auch int raw-values, aber ich muss nicht alle Aufzählungsmitglieder in separaten Eigenschaften wiederholen. 

UPDATE Xcode 6.1 hat ein bisschen geändert, wie man ein Enumerationsmitglied mit einem Rohwert erhält, also habe ich die Auflistung korrigiert. Kleiner Fehler mit falschem ersten Rohwert behoben

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<ValidSuits> in
                var i=0
                return GeneratorOf<ValidSuits>{
                    return ValidSuits(rawValue: i++)
                }
            }
        )
    }
}
2
gleb vodovozov

Enums haben die Methoden toRaw () und fromRaw (). Wenn Ihr Rohwert ein Int ist, können Sie von der ersten bis zur letzten Enumeration iterieren:

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()
    }
}

Ein Grund dafür ist, dass Sie vor dem Ausführen der simpleDescription-Methode auf optionale Werte testen müssen. Daher setzen Sie convertSuit zuerst auf unseren Wert und dann eine Konstante auf convertSuit.simpleDescription ()

Dies ist ein ziemlich alter Beitrag aus Swift 2.0. Es gibt jetzt einige bessere Lösungen, die neuere Funktionen von Swift 3.0 verwenden: Iteration durch ein Enum in Swift 3.0

Und zu dieser Frage gibt es eine Lösung, die ein neues Feature von (das noch nicht veröffentlichte, während ich diesen Beitrag schreibe) Swift 4.2: verwendet.


Es gibt viele gute Lösungen in diesem Thread und andere, jedoch sind einige von ihnen sehr kompliziert. Ich mag es, so viel wie möglich zu vereinfachen. Hier ist eine Lösung, die möglicherweise für unterschiedliche Bedürfnisse funktioniert, aber ich denke, dass sie in den meisten Fällen gut funktioniert: 

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
    }
}

Zu iterieren:

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

Dies scheint ein Hack zu sein, aber wenn Sie rohe Werte verwenden, können Sie so etwas tun

enum Suit: Int {  
    case Spades = 0, Hearts, Diamonds, Clubs  
 ...  
}  

var suitIndex = 0  
while var suit = Suit.fromRaw(suitIndex++) {  
   ...  
}  
2
KenH

Hier eine Methode, die ich verwende, um eine Aufzählung zu durchlaufen und mehrere Wertetypen aus einer Aufzählung bereitzustellen

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"))")

Dies ist die Ausgabe:

Die Nummer Null in Französisch: Zéro, Spanisch: Cero, Japanisch: Nuru
Die Nummer Eins in Französisch: un, Spanisch: Uno, Japanisch: Ichi
Die Nummer Zwei in Französisch: Deux, Spanisch: Dos, Japanisch: Ni
Die Nummer Drei in Französisch: Trois, Spanisch: Tres, Japanisch: San
Die Nummer Vier auf Französisch: Quatre, Spanisch: Cuatro, Japanisch: Shi
Die Nummer Fünf in Französisch: Cinq, Spanisch: Cinco, Japanisch: Los
Die Nummer Sechs in Französisch: Sechs, Spanisch: Seis, Japanisch: Roku
Die Nummer Sieben in Französisch: Sept, Spanisch: Siete, Japanisch: Shichi

Insgesamt 8 Fälle

siete auf japanisch: shichi


UPDATE

Ich habe vor kurzem ein Protokoll für die Aufzählung erstellt. Das Protokoll erfordert eine Aufzählung mit einem Int-Rohwert:

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
    }
}
2
MSimic

Hier ist mein vorgeschlagener Ansatz. Es ist nicht völlig zufriedenstellend (ich bin sehr neu in Swift und OOP!), Aber vielleicht kann jemand es verfeinern. Die Idee ist, dass jedes Enum seine eigenen Bereichsinformationen als erste und letzte Eigenschaft bereitstellt. Es fügt jeder Aufzählung nur zwei Zeilen Code hinzu: immer noch ein wenig hartcodiert, aber zumindest wird nicht der gesamte Satz dupliziert. Es ist nicht erforderlich, die Suit-Enumeration so zu ändern, dass sie ein Int ist, wie es bei der Rank-Enumeration der Fall ist. 

Anstatt die gesamte Lösung zu wiederholen, ist hier der Code, den ich zur Rank-Aufzählung hinzugefügt habe, irgendwo nach den Case-Anweisungen (Suit-Enum ist ähnlich):

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

und die Schleife, mit der ich das Deck als String-Array erstellt habe. (In der Problemdefinition wurde nicht angegeben, wie das Deck strukturiert werden soll.)

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
}

Dies ist unbefriedigend, da die Eigenschaften einem Element und nicht der Aufzählung zugeordnet sind. Die 'for'-Schleifen werden jedoch klarer. Ich möchte, dass Rank.first anstelle von Rank.Ace.first gesagt wird. Es funktioniert (mit jedem Element), aber es ist hässlich. Kann jemand zeigen, wie man das auf das Enumenniveau erhöht?

Damit das funktioniert, habe ich die createDeck-Methode aus der Card-Struktur genommen. Ich konnte nicht herausfinden, wie ein [String] -Array von dieser Struktur zurückgegeben wird, und das scheint ein schlechter Ort für eine solche Methode zu sein.

2
Roger Worden

Eine andere Lösung: 

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..<Suit.count {
    print(Suit(index: i).rawValue)
}
2
Miguel Gallego
enum Rank: Int
{
    case Ace = 0
    case Two, Three, Four, Five, Six, Seve, Eight, Nine, Ten
    case Jack, Queen, King
    case Count
}

enum Suit : Int
{
    case Spades = 0
    case Hearts, Diamonds, Clubs
    case Count
}

struct Card
{
    var rank:Rank
    var suit:Suit
}

class Test
{
    func makeDeck() -> Card[]
    {
        let suitsCount:Int = Suit.Count.toRaw()
        let rankCount:Int = Rank.Count.toRaw()
        let repeatedCard:Card = Card(rank:Rank.Ace, suit:Suit.Spades)
        let deck:Card[] = Card[](count:suitsCount*rankCount, repeatedValue:repeatedCard)

        for i:Int in 0..rankCount
        {
            for j:Int in 0..suitsCount
            {
                deck[i*suitsCount+j] = Card(rank: Rank.fromRaw(i)!, suit: Suit.fromRaw(j)!)
            }
        }
        return deck
    }
}

Basierend auf Rick Antwort: Das ist 5 mal schneller

1

(Verbesserung der Antwort von Karthik Kumar)

Diese Lösung verwendet den Compiler, um sicherzustellen, dass Sie keinen Fall verpassen.

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

    static var enumerate: [Suit] {
        switch Suit.spades {
        // make sure the two lines are identical ^_^
        case        .spades, .hearts, .diamonds, .clubs:
            return [.spades, .hearts, .diamonds, .clubs]
        }
    }
}
1
Cœur

Es gibt einen klugen Weg, und es ist frustrierend, da es den Unterschied zwischen den zwei verschiedenen Arten von Enummen veranschaulicht.

Versuche dies:

    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
    }

Der Deal ist, dass eine Enumeration, die durch Zahlen (Rohwerte) unterstützt wird, implizit explizit geordnet ist, während eine Enumeration, die nicht durch Zahlen unterlegt ist, explizit implizit ungeordnet ist.

Z.B. Wenn wir die Aufzählungswerte angeben, ist die Sprache gerissen genug, um herauszufinden, in welcher Reihenfolge die Zahlen sind .. Wenn wir dagegen keine Reihenfolge angeben, versuchen wir, die Sprache durch die Werte zu iterieren wirft seine Hände in die Luft und geht "ja, aber welche willst du zuerst machen ???"

Andere Sprachen, die dies tun können (Iterieren über ungeordnete Enumerationen), können dieselben Sprachen sein, in denen sich alles unter der Haube befindet, eigentlich eine Karte oder ein Wörterbuch, und Sie können über die Schlüssel einer Map iterieren, ob es eine logische Reihenfolge gibt oder nicht.

Der Trick besteht also darin, etwas explizit zu ordnen, in diesem Fall Fälle der Farben eines Arrays in der gewünschten Reihenfolge. Sobald Sie es geben, ist Swift wie "Nun, warum haben Sie das überhaupt nicht gesagt?"

Der andere Kurztrick besteht darin, den Forcen-Operator für die fromRaw-Funktion zu verwenden. Dies verdeutlicht ein weiteres "Gotcha" über Enumerationen, dass der Bereich der möglichen Werte, die übergeben werden können, oft größer ist als der Enumerationsbereich. Wenn wir beispielsweise Rank.fromRaw (60) sagen, wird kein Wert zurückgegeben. Daher verwenden wir die Option optional der Sprache. Wo wir mit der Verwendung von Optionals beginnen, wird das Forcen bald folgen. (Oder alternativ die if let -Konstruktion, die mir immer noch ein bisschen komisch erscheint)

1
Rick

Swift 5 Lösung: Die Lösung in Swift 5 ist ganz einfach:

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

// then access the cases like this:

for suitKey in LocalizationKey.allCases {
    print(suitKey)
}
1
J.D. Wooder

Ich habe die Methode unten verwendet, die Annahme ist, dass ich weiß, welcher der letzte Wert in der Rank-Aufzählung ist und dass alle Ränge inkrementelle Werte nach Ace haben

Ich bevorzuge diesen Weg, da er sauber und klein ist und leicht verständlich ist

 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
}
1
Ninad Shah

In einigen Fällen handelt es sich möglicherweise um einen aufgezählten Typ mit einem zugrunde liegenden rohen Integer-Typ, der sich während des gesamten Lebenszyklus der Softwareentwicklung ändert. Hier ist ein Beispiel, das für diesen Fall gut funktioniert:

public class MyClassThatLoadsTexturesEtc
{
    //...

    // Colors used for gems and sectors.
    public enum Color: Int
    {
        // Colors arranged in order of the spectrum.
        case First = 0
        case Red, Orange, Yellow, Green, Blue, Purple, Pink
        // --> Add more colors here, between the first and last markers.
        case Last
    }

    //...

    public func preloadGems()
    {
        // Preload all gems.
        for i in (Color.First.toRaw() + 1) ..< (Color.Last.toRaw())
        {
            let color = Color.fromRaw(i)!
            loadColoredTextures(forKey: color)
        }
    }

    //...
}
0
Byron Formwalt

Ich brauchte ein wenig mehr als nur eine Methode in der Struktur, wie das von Swift geforderte Buch, aber ich habe die nächsten Funktionen in der Enumeration eingerichtet. Ich hätte ein Protokoll verwendet. Ich bin mir nicht sicher, warum es so ist

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seve, 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.toRaw())
        }
    }
    mutating func next() -> Rank {
        var rank = self
        var rawrank = rank.toRaw()
        var nrank:Rank = self
        rawrank = rawrank + 1
        if let newRank = Rank.fromRaw(rawrank) {
            println("\(newRank.simpleDescription())")
            nrank = newRank
        } else {
            return self
        }
        return nrank
    }
}

enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    func color() -> String {
        switch self{
        case .Spades, .Clubs:
            return "black"
        default:
            return "red"
        }
    }
    func simpleDescription() -> String {
        switch self{
        case .Spades:
            return "spades"
        case .Hearts:
            return "hearts"
        case .Diamonds:
            return "diamonds"
        case .Clubs:
            return "clubs"
        }
    }
    mutating func next() -> Suit {
        switch self{
        case .Spades:
            return Hearts
        case .Hearts:
            return Diamonds
        case .Diamonds:
            return Clubs
        case .Clubs:
            return Spades
        }
    }
}

struct Card {
    var rank:Rank
    var suit:Suit
    func deck() -> Card[] {
        var tRank = self.rank
        var tSuit = self.suit
        let tcards = 52 // we start from 0
        var cards: Card[] = []
        for i in 0..tcards{
            var card = Card(rank: tRank, suit: tSuit)
            cards.append(card)
            tRank = tRank.next()
            tSuit = tSuit.next()
        }
        return cards
    }
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}

var card = Card(rank: .Ace, suit: .Spades)
var deck = card.deck()

ich hoffe, das hilft im Grunde ein wenig allgemeines Wissen, aber das lässt sich leicht durch Multiplizieren von Anzügen nach Rang korrigieren (wenn Sie kein Standard-Kartendeck verwenden und Sie die Enummen entsprechend ändern müssen und im Grunde nur durchlaufen müssen.) Um die Zeit zu sparen, habe ich verschiedene Werte verwendet. Ich habe Ränge verwendet, die Sie für Anzüge verwenden könnten

0
Snymax

Ich habe die Funktion count () hinzugefügt und die Werte iteriert:

public enum MetricType : Int {
case mvps = 0
case allNBA = 1
case championshipRings = 2
case finalAppearances = 3
case gamesPlayed = 4
case ppg = 5

static func count() -> Int {
    return (ppg.rawValue) + 1
}

static var allValues: [MetricType] {
    var array: [MetricType] = Array()
    var item : MetricType = MetricType.mvps
    while item.rawValue < MetricType.count() {
        array.append(item)
        item = MetricType(rawValue: (item.rawValue + 1))!
    }
    return array
}

}

0
Mihaela

Meine Lösung ist, ein Array mit allen Aufzählungsmöglichkeiten zu deklarieren, damit alle durchlaufen werden können.

//Function inside struct Card
static func generateFullDeck() -> [Card] {
    let allRanks = [Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King]
    let allSuits = [Suit.Hearts, Suit.Diamonds, Suit.Clubs, Suit.Spades]
    var myFullDeck: [Card] = []

    for myRank in allRanks {
        for mySuit in allSuits {
            myFullDeck.append(Card(rank: myRank, suit: mySuit))
        }
    }
    return myFullDeck
}

//actual use:
let aFullDeck = Card.generateFullDeck()    //Generate the desired full deck

var allDesc: [String] = []
for aCard in aFullDeck {
    println(aCard.simpleDescription())    //You'll see all the results in playground
}
0
Jeff Chen

Ich fand ein etwas hässliches Gefühl, aber viel sicherer, dies zu tun, ohne die Werte zweimal einzugeben oder auf das Gedächtnis der enum-Werte zu verweisen.

Erstellen Sie statt einer Aufzählung eine Struktur mit einer einzelnen Instanz und alle Konstanten der Aufzählungswerte. Die Variablen können dann mit einer Mirror abgefragt werden.

public struct Suit{

    // the values
    let spades = "♠"
    let hearts = "♥"
    let diamonds = "♦"
    let clubs = "♣"

    // make a single instance of the Suit struct, Suit.instance
    struct SStruct{static var instance: Suit = Suit()}
    static var instance : Suit{
        get{return SStruct.instance}
        set{SStruct.instance = newValue}
    }

    // an array with all of the raw values
    static var allValues: [String]{
        var values = [String]()

        let mirror = Mirror(reflecting: Suit.instance)
        for (_, v) in mirror.children{
            guard let suit = v as? String else{continue}
            values.append(suit)
        }

        return values
    }
}

Wenn Sie diese Methode verwenden, müssen Sie zum Abrufen eines einzelnen Werts Suit.instance.clubs oder Suit.instance.spades verwenden.

Aber das alles ist so langweilig.

public struct SuitType{

    // store multiple things for each suit
    let spades = Suit("♠", order: 4)
    let hearts = Suit("♥", order: 3)
    let diamonds = Suit("♦", order: 2)
    let clubs = Suit("♣", order: 1)

    struct SStruct{static var instance: SuitType = SuitType()}
    static var instance : SuitType{
        get{return SStruct.instance}
        set{SStruct.instance = newValue}
    }

    // a dictionary mapping the raw values to the values
    static var allValuesDictionary: [String : Suit]{
        var values = [String : Suit]()

        let mirror = Mirror(reflecting: SuitType.instance)
        for (_, v) in mirror.children{
            guard let suit = v as? Suit else{continue}
            values[suit.rawValue] = suit
        }

        return values
    }
}

public struct Suit: RawRepresentable, Hashable{
    public var rawValue: String
    public typealias RawValue = String

    public var hashValue: Int{
        // find some integer that can be used to uniquely identify
        // each value. In this case, we could have used the order
        // variable because it is a unique value, yet to make this
        // apply to more cases, the hash table address of rawValue
        // will be returned, which should work in almost all cases
        // 
        // you could also add a hashValue parameter to init() and
        // give each suit a different hash value
        return rawValue.hash
    }

    public var order: Int
    public init(_ value: String, order: Int){
        self.rawValue = value
        self.order = order
    }

    // an array of all of the Suit values
    static var allValues: [Suit]{
        var values = [Suit]()

        let mirror = Mirror(reflecting: SuitType.instance)
        for (_, v) in mirror.children{
            guard let suit = v as? Suit else{continue}
            values.append(suit)
        }

        return values
    }

    // allows for using Suit(rawValue: "♦"), like a normal enum
    public init?(rawValue: String){
        // get the Suit from allValuesDictionary in SuitType, or return nil if that raw value doesn't exist
        guard let suit = SuitType.allValuesDictionary[rawValue] else{return nil}
        // initialize a new Suit with the same properties as that with the same raw value
        self.init(suit.rawValue, order: suit.order)
    }
}

Du kannst jetzt Sachen machen

let allSuits: [Suit] = Suit.allValues

oder

for suit in Suit.allValues{
   print("The suit \(suit.rawValue) has the order \(suit.order)")
}

Um eine Single zu erhalten, müssen Sie jedoch SuitType.instance.spades oder SuitType.instance.hearts verwenden. Um dies ein wenig intuitiver zu gestalten, können Sie Suit etwas Code hinzufügen, mit dem Sie Suit.type.* anstelle von SuitType.instance.* verwenden können.

public struct Suit: RawRepresentable, Hashable{
   // ...your code...

   static var type = SuitType.instance

   // ...more of your code...
}

Sie können jetzt Suit.type.diamonds anstelle von SuitType.instance.diamonds oder Suit.type.clubs anstelle von SuitType.instance.clubs verwenden.

0
Jojodmo

Anpassung von @ rintaros Antwort an Swift 3, in dem rintaro:

  • schrieb eine Hilfsfunktion iterateEnum() für das Durchlaufen von Fällen für beliebige Aufzählungstypen
  • umsetzung der Casting-Ideen aus @ Kametrixoms Antwort

Swift3

func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
    var i = 0
    return AnyGenerator {
        let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }

        let value : T?
        if next.hashValue == i {
            value = next
        } else {
            value = nil
        }
        i = i + 1
        return value
    }
}
0
yo.ian.g