607 Stimmen

Wie nummeriert man einen Aufzählungstyp mit String-Typ?

enum Suit: String {
    case spades = ""
    case hearts = ""
    case diamonds = ""
    case clubs = ""
}

Zum Beispiel, wie kann ich so etwas machen:

for suit in Suit {
    // Bearbeite etwas mit dem Anzug
    print(suit.rawValue)
}

Ergebnisbeispiel:

26voto

RndmTsk Punkte 1694

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

Das ForwardIndexType-Protokoll erfordert, dass Sie eine successor()-Funktion definieren, um durch die Elemente zu navigieren.

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

    // ... andere Funktionen

    // Option 1 - Per Hand herausfinden
    func successor() -> Rank {
        switch self {
            case .Ace:
              return .Two
            case .Two:
              return .Three

            // ... usw.

            default:
              return .King
        }
    }

    // Option 2 - Definieren Sie einen Operator!
    func successor() -> Rank {
        return self + 1
    }
}

// HINWEIS: Der Operator wird AUSSERHALB der Klasse definiert
func + (left: Rank, right: Int) -> Rank {
    // Ich benutze hier to/from raw, aber wieder, Sie können eine case-Anweisung
    // oder was auch immer Ihnen einfällt

    return left == .King ? .King : Rank(rawValue: left.rawValue + right)!
}

Bei der Iteration über einen offenen oder geschlossenen Bereich (..< oder ...) wird intern die successor()-Funktion aufgerufen, was es Ihnen ermöglicht, Folgendes zu schreiben:

// Unter der Haube werden successor(Rank.King) und successor(Rank.Ace) aufgerufen, um Grenzen festzulegen
for r in Rank.Ace...Rank.King {
    // Mach etwas Nützliches
}

19voto

Dilip Tiwari Punkte 1351

Aktualisierter Code : Swift 4.2/Swift 5

enum Suit: String, CaseIterable {
   case spades = ""
   case hearts = ""
   case diamonds = ""
   case clubs = ""
}

Um den Output gemäß der Frage abzurufen:

for suitKey in Suit.allCases {
    print(suitKey.rawValue)
}

Output :

CaseIterable: bietet eine Sammlung aller seiner Werte. Typen, die das CaseIterable-Protokoll erfüllen, sind typischerweise Enumerationen ohne zugeordnete Werte. Bei Verwendung eines CaseIterable-Typs können Sie auf eine Sammlung aller Fälle des Typs zugreifen, indem Sie die allCases-Eigenschaft des Typs verwenden.

Zum Abrufen der Fälle verwenden wir .allCases. Weitere Informationen finden Sie unter https://developer.apple.com/documentation/swift/caseiterable

18voto

adazacom Punkte 443

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
}

Vor 4.2:

Ich mag diese Lösung, die ich gefunden habe nachdem ich "List comprehension in Swift" entdeckt habe.

Sie verwendet Int raws anstelle von Strings, aber sie vermeidet doppelte Eingaben, erlaubt die Anpassung der Bereiche und codiert keine Raw-Werte fest ein.

Dies ist eine Swift 4 Version meiner Originallösung, aber siehe die oben genannte 4.2 Verbesserung:

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
}

17voto

Alfa07 Punkte 3174

Im Prinzip ist es möglich, es auf diese Weise zu tun, vorausgesetzt, dass Sie keine Zuweisung von Rohwerten für die Fälle von Enums 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 {
        return SequenceOf({ RankEnumGenerator() })
    }
}

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

16voto

Senseful Punkte 79049

Wenn Sie dem Enum einen Rohwert als Ganzzahlwert geben, wird das Schleifen deutlich einfacher.

Zum Beispiel können Sie anyGenerator verwenden, um einen Generator zu bekommen, der über Ihre Werte aufzählen kann:

enum Suit: Int, CustomStringConvertible {
    case Spades, Hearts, Diamonds, Clubs
    var description: String {
        switch self {
        case .Spades:   return "Pik"
        case .Hearts:   return "Herzen"
        case .Diamonds: return "Karo"
        case .Clubs:    return "Kreuz"
        }
    }
    static func enumerate() -> AnyGenerator {
        var nextIndex = Spades.rawValue
        return anyGenerator { Suit(rawValue: nextIndex++) }
    }
}
// Jetzt können Sie es so verwenden:
for suit in Suit.enumerate() {
    suit.description
}
// oder so:
let allSuits: [Suit] = Array(Suit.enumerate())

Allerdings sieht das wie ein ziemlich übliches Muster aus, wäre es nicht schön, wenn wir jede Enum-Typ einfach durch Konformität zu einem Protokoll aufzählbar machen könnten? Mit Swift 2.0 und Protokollerweiterungen ist das jetzt möglich!

Fügen Sie einfach dies zu Ihrem Projekt hinzu:

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

Jetzt, jedes Mal wenn Sie ein Enum erstellen (solange es einen Int Rohwert hat), können Sie es durch Konformität zu dem Protokoll aufzählbar machen:

enum Rank: Int, EnumerableEnum {
    case Ass, Zwei, Drei, Vier, Fünf, Sechs, Sieben, Acht, Neun, Zehn, Bube, Dame, König
}
// ...
for rank in Rank.enumerate() { ... }

Wenn Ihre Enum-Werte nicht mit 0 beginnen (der Standardwert), überschreiben Sie die Methode firstRawValue:

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

Die endgültige Suit-Klasse, inklusive Ersetzung von simpleDescription durch das Standardprotocol CustomStringConvertible, wird so aussehen:

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

Swift 3-Syntax:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X