web-dev-qa-db-ja.com

文字列型の列挙型を列挙する方法

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

たとえば、次のようにします。

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

結果の例:

♠
♥
♦
♣
485
Lucien

Swift 4.2以降

Swift 4.2 (Xcode 10以降)から始めて、CaseIterableの恩恵を受けられるようにallCasesにプロトコル準拠を追加するだけです。

extension Suit: CaseIterable {}

それからこれはすべての可能な値を表示します。

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

以前のSwiftバージョン(3.xおよび4.x)との互換性

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
195
Cœur

この投稿はここに関連しています https://www.Swift-studies.com/blog/2014/6/10/enumerating-enums-in-Swift

基本的に提案された解決策は

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

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

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

任意のenum型のケースを繰り返すためのユーティリティ関数iterateEnum()を作りました。

使用例は次のとおりです。

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

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

出力:

♠
♥
♦
♣

しかし、これは デバッグまたはテスト専用です。 目的:これは文書化されていない現在の(Swift1.1)コンパイラの動作に依存します。だから、あなた自身の責任でそれを使用してください:)

これがコードです:

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

基本的な考え方は次のとおりです。

  • enumのメモリ表現(関連する型を含むenumsを除く)は、単なるケースのインデックスです。ケースの数が2...256の場合はUInt8と同一、257...65536の場合はUInt16となります。それで、それは対応する符号なし整数型からのunsafeBitcastになることができます。
  • enum値の.hashValueは、ケースのインデックスと同じです。
  • invalid indexからビットキャストされたenum値の.hashValue0です

追加:

Swift2用に改訂され、 @ Kametrixomの答えからキャストのアイデアが実装されました

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

追加: 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
    }
}

追加: 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

他の解決策 仕事 しかし、それらはすべて、例えば可能なランクやスーツの数、あるいは最初と最後のランクが何であるかという仮定をしています。確かに、カードのデッキのレイアウトはおそらく近い将来変わらないでしょう。しかし、一般的には、できる限り仮定を少なくするようなコードを書くのは適切ではありません。私の解決策:

私はスーツのenumに生の型を追加したので、SuitのケースにアクセスするためにSuit(rawValue :)を使用することができます。

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

CardのcreateDeck()メソッドの実装以下。 init(rawValue :)は無効な初期化子であり、オプションを返します。両方のwhileステートメントのラップを解除してその値をチェックすることによって、RankまたはSuitケースの数を仮定する必要はありません。

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

CreateDeckメソッドを呼び出す方法は次のとおりです。

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

本当にうまくいく2番目の答え

それで私はビットとバイトに遭遇して拡張を作成しました(後で私は @ rintaro の答えに非常によく似た作品を見つけました)。こんな感じで使えます:

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

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

注目に値するのは、(関連する値なしで)あらゆる列挙型で使えるということです。これは、ケースがない列挙型には機能しないことに注意してください。

免責事項

@ rintaro の答えと同様に、このコードはenumの基礎となる表現を使用します。この表現は文書化されておらず、将来変更される可能性があります。壊れてしまう可能性があります - >私は本番環境でこれを使用することはお勧めしません。

コード(Swift 2.2、Xcode 7.3.1、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
            }
        }
    }
}

コード(Swift 3、Xcode 8.1、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
            }
        }
    }
}

(なぜtypealiasが必要なのか私にはわかりませんが、コンパイラはそれなしで文句を言います)

(私はこの答えを大きく修正しました。過去のバージョンの編集を見てください)

72
Kametrixom

ForwardIndexTypeプロトコルを実装することで列挙型を反復処理できます。

ForwardIndexTypeプロトコルでは、要素をステップスルーするためにsuccessor()関数を定義する必要があります。

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

開いている範囲または閉じている範囲(..<または...)を繰り返し処理すると、内部的にsuccessor()関数が呼び出され、これを記述できます。

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

原則として、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<RankEnum> {
    return SequenceOf<RankEnum>({ RankEnumGenerator() })
  }
}

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

この問題ははるかに簡単になりました。これが私のSwift 4.2ソリューションです。

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
}

プレ4.2

私はこのページを見つけた後にまとめたこの解決策が好きです: Swiftでのリスト内包表記

これは、文字列の代わりにInt rawを使用しますが、2回入力することを避け、範囲のカスタマイズを可能にし、raw値をハードコードしません。

これは私の最初の解決策のSwift 4バージョンですが、上記の4.2の改善を見てください。

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

もしあなたがenum 生のInt値を与えれば それはループをずっと簡単にするでしょう。

たとえば、anyGeneratorを使用して、自分の値を列挙できるジェネレータを取得できます。

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

しかし、これはかなり一般的なパターンのように見えます。単にプロトコルに準拠することで列挙型を列挙可能にできればいいのではないでしょうか。 Swift 2.0とプロトコルの拡張機能を使えば、今は可能です。

これをプロジェクトに追加するだけです。

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

列挙型を作成するときはいつでも(それがInt生の値を持つ限り)、プロトコルに準拠することによってそれを列挙可能にすることができます。

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

列挙値が0(デフォルト)で始まっていない場合は、firstRawValueメソッドをオーバーライドします。

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

simpleDescriptionより標準的なCustomStringConvertibleプロトコル に置き換えることを含む、最後のSuitクラスは次のようになります。

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

編集:

Swift 3の構文:

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

Swift 2.2 +に更新

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

swift 2.2のフォームに更新されたコード @ Kametrixom's an swer

Swift 3.0+ の場合( @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

私は自分のコードを通して.allValuesをたくさんやっていました。私はついにIteratableプロトコルに準拠し、rawValues()メソッドを持つ方法を考え出しました。

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

編集: スイフトエボリューションの提案 SE-0194列挙型の派生コレクション この問題に向けたレベルを提案する ソリューション 。 Swift 4.2以降で見られます。この提案はまたいくつかの 回避策を指摘しています それはここで既に述べたものと似ていますが、それでもなお見るのは興味深いかもしれません。

私はまた完全性のために私の元の記事を残します。


これは@ Peymmankhの答えに基づいた、さらに別のアプローチで、 Swift 3 に適応しています。

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

これはどう?

5
Mossila

すみません、私の答えは私がしなければならなかったことの中で私がこの記事をどのように使ったかに特定されました。 enum内で 検索 ケースを検索する方法を探しているこの質問につまずく人のために、これはそれをする方法です(Swift 2で新しい):

編集:小文字のcamelCaseがSwift 3のenum値の標準になりました

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

列挙型の列挙について疑問に思っている人のために、すべての列挙型の値の配列を含む静的var/letを含むこのページで与えられた答えは正しいです。 tvOS用の最新のAppleサンプルコードには、これとまったく同じテクニックが含まれています。

そうは言っても、彼らはその言語にもっと便利なメカニズムを組み入れるべきです(Apple、あなたは聞いていますか?)

4
Gene Loparco

Swift 4.2によるXcode 10

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

あれを呼べ

print(Filter.allValues)

プリント:

[「給与」、「経験」、「テクノロジー」、「未利用」、「未利用の高価値」]


古いバージョン

enumIntを表す場合

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

このようにそれを呼ぶ:

print(Filter.allValues)

プリント:

[0、1、2、3、4]


enumStringを表す場合

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

あれを呼べ

print(Filter.allValues)

プリント:

[「給与」、「経験」、「テクノロジー」、「未利用」、「未利用の高価値」]

4

Swift 3では、基礎となるenumに{rawValue}があるとき、{Strideable}プロトコルを実装できます。利点は、他のいくつかの提案のように値の配列が作成されないこと、そして標準のSwiftの "for i in ..."ステートメントが機能することで、Nice構文になります。

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

あなたはこのように列挙しようとすることができます

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

これは私がやっと行ったものです。読みやすさと保守性の適切なバランスが取れていると思います。

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

実験は次のとおりです。

ランクとスーツの各組み合わせの1枚のカードで、カードの完全なデッキを作成するメソッドをCardに追加します。

それで、メソッドを追加する以外に与えられたコードを修正したり拡張したりすることなく(そしてまだ教えられていないものを使わずに)、私はこの解決策を思い付きました:

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

Swift 2.0を扱う間に、ここに私の提案があります:

生の型をSuitに追加しましたenum

enum Suit: Int {

その後:

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

@Kametrixom answer here と同じように、配列を返すほうがAnySequenceを返すよりも優れていると思います。カウントなどのArrayのすべての機能にアクセスできるからです。

これが書き換えです。

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

すべての値の配列を返す計算プロパティを使用しました(この記事のおかげで http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ )。しかし、それはint raw-valuesも使用しますが、列挙のすべてのメンバを別々のプロパティで繰り返す必要はありません。

_ update _ Xcode 6.1は生の値を使ってenumメンバーを取得する方法を少し変更したので、リストを修正しました。最初の生の値が間違っているという小さなエラーも修正

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

列挙型にはtoRaw()およびfromRaw()メソッドがあるので、生の値がIntの場合は、最初の列挙から最後の列挙まで繰り返すことができます。

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

1つの問題は、simpleDescriptionメソッドを実行する前にオプションの値をテストする必要があることです。そのため、最初にconversionSuitを自分の値に設定し、次に定数をconvertSuit.simpleDescription()に設定します。

これはSwift 2.0からのかなり古い投稿です。ここにSwift 3.0のより新しい機能を使用するいくつかのより良い解決策があります: Swift 3.0のEnumを通して反復

そしてこの質問に関しては、(私がこの編集を書いているときにはまだリリースされていない)Swift 4.2の新機能を使った解決策があります: Swift enumのカウントをどうやって取得できますか?


このスレッドや他のスレッドには良い解決策がたくさんありますが、そのうちのいくつかは非常に複雑です。できるだけ単純化するのが好きです。これは、さまざまなニーズに対して機能する可能性がある、または機能しない可能性があるソリューションです。ただし、ほとんどの場合はうまく機能すると思います。

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

繰り返すには:

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

これはハックのように思えますが、生の値を使用すれば、次のようなことができます。

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

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

ここで私が使っているのは、enumを繰り返し処理する方法と、1つの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"))")

これは出力です:

数字のゼロフランス語:zéro、スペイン語:cero、日本語:nuru
ナンバーワンのフランス語:un、スペイン語:uno、日本語:ichi
フランス語の数字2:deux、スペイン語:dos、日本語:ni
フランス語の数字3:トロイ、スペイン語:トレス、日本語:サン
フランス語の数4:quatre、スペイン語:cuatro、日本語:shi
フランスの数5:cinq、スペイン語:cinco、日本語:go
フランス語の数6:6、スペイン語:seis、日本語:roku
フランス語の7つの数:9月、スペイン語:siete、日本語:shichi

計8件

日本語のシーエイト:shichi


_ update _

列挙を処理するためのプロトコルを最近作成しました。このプロトコルでは、生のInt値を持つenumが必要です。

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

これが私の提案したアプローチです。それは完全に満足のいくものではありません(私はSwiftとOOPの初心者です)!おそらく誰かがそれを改良することができます。アイデアはそれぞれのenumに.firstと.lastプロパティとしてそれ自身の範囲情報を提供させることです。それは各enumに2行のコードを追加するだけです:それでも少しハードコードされています、しかし少なくともそれはセット全体を複製することではありません。 Rank列挙型のように、型指定されていない代わりに、Suit列挙型をIntに変更する必要があります。

ソリューション全体をエコーするのではなく、caseステートメントの後のどこかにランク列挙に追加したコードです(Suit enumも同様です)。

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

そして、デッキをStringの配列として構築するために使用したループ。 (問題の定義は、デッキがどのように構成されるべきかを述べていませんでした。)

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
}

プロパティは列挙型ではなく要素に関連付けられているため、不十分です。しかし、それは 'for'ループを明確にします。 Rank.Ace.firstではなくRank.firstと言ってもらいたいのですが。それは(どんな要素でも)働きますが、それは醜いです。誰かがそれをenumレベルに上げる方法を示すことができますか?

そしてそれを機能させるために、createDeckメソッドをCard構造体から外しました...その構造体から返される[String]配列を取得する方法を理解することができませんでした。

2
Roger Worden

別の解決策:

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

Rickの回答に基づく:これは5倍高速です

1

(Karthik Ku​​mar回答の改善)

この解決策はあなたがケースを見逃すことがないことを保証するためにコンパイラを使用しています。

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

賢い方法があり、それがそうであるようにイライラすることは2つの異なる種類のenumの間の違いを示しています。

これを試して:

    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
    }

数字で裏付けられたenumは暗黙的に明示的に順序付けられているのに対し、数字で裏付けられたenumは暗黙的に明示的に順序付けられています。

例えば。 enum値に数を与えると、その数がどんな順序で並んでいるのかを理解するのに十分なほど賢い言語になります。空中で立ち上がって"はい、でもどちらを先に行きたいですか???"

これを実行できる他の言語(順序付けされていない列挙型の繰り返し)は、すべてが実際には地図や辞書であり、論理的な順序があるかどうかにかかわらず、地図のキーを繰り返し使用できます。

したがって、トリックは、明示的に順序付けされたもの、この場合は目的の順序で配列内のスーツのインスタンスを提供することです。あなたがそれを与えるとすぐに、Swiftは"そもそもなぜそんなこと言わなかったの?"

もう1つの簡単な方法は、fromRaw関数で強制演算子を使用することです。これは、列挙型に関するもう1つの「問題点」を示しています。渡すことが可能な値の範囲は、多くの場合、列挙型の範囲よりも大きいということです。たとえば、Rank.fromRaw(60)と言った場合、値は返されないので、言語の optional 機能を使用しています。オプションの使用を開始したところでは、すぐに強制が行われます。 (あるいは、やや奇妙に思えるかもしれませんが、代わりにlet ifという構造になります)

1
Rick

Swift 5の解決策: / Swift 5の解決策はとても簡単です。

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

以下の方法を使用しました。仮定は、どちらがランク列挙の最後の値であり、すべてのランクがAceの後に増分値を持つかを知っていることです

私はそれが清潔で小さく、理解しやすいのでこの方法を好む

 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

場合によっては、ソフトウェア開発のライフサイクルを通して変化する、基礎となる生の整数型を持つ列挙型を扱うことがあります。これはその場合によく働く例です:

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

Swiftの本が要求するような構造体の中の1つのメソッドよりも少しだけ時間がかかりましたが、私はenumに次の関数を設定しました。私はなぜか分からないプロトコルを使用していたでしょうが、intとしてランクセットを持つことはそれをめちゃくちゃにします

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

これが基本的に私が少し一般的な知識を使った助けになることを願っていますが、それは訴訟にランクを掛けることによって容易に直すことができます。私が使った時間を節約するための異なる列挙型のメモはあなたが望むならスーツのためにあなたが同じことをすることができる生の値をランク付けするしかし例はそれを持っていなかった

0
Snymax

関数count()を追加して、値を繰り返します。

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

私の解決策は、すべてのenumの可能性を持つ配列を宣言することです。そのため、それらすべてを通過することができます。

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

やや厄介だがもっと安全な方法で、値を2回入力したり、enum値のメモリを参照したりする必要がないので、壊れる可能性は非常に低い。

基本的には、enumを使用する代わりに、単一のインスタンスで構造体を作り、すべてのenum-values定数を作ります。変数はMirrorを使って問い合わせることができます。

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

この方法を使用する場合、単一の値を取得するにはSuit.instance.clubsまたはSuit.instance.spadesを使用する必要があります。

しかし、それはすべてとても退屈です...これをもっと本当のenumのようにするためのいくつかのことをしましょう!

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

これで、こんなことができます

let allSuits: [Suit] = Suit.allValues

または

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

ただし、シングルを入手するには、SuitType.instance.spadesまたはSuitType.instance.heartsを使用する必要があります。これをもう少し直感的にするために、SuitSuit.type.*の代わりにSuitType.instance.*を使用できるようにするコードを追加できます

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

   static var type = SuitType.instance

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

Suit.type.diamondsの代わりにSuitType.instance.diamondsを、またはSuit.type.clubsの代わりにSuitType.instance.clubsを使用できるようになりました

0
Jojodmo

@ rintaroの答え /をSwift 3に適応させるrintaro:


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