String型の列挙型を列挙する方法は?


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

たとえば、次のようにするにはどうすればよいですか。

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

結果の例:



どのような場合にタイプを知らないでしょうか?
mtbennett 2014年

そうです、この場合は文字列型です。
Lucien

Swiftにはまだ反映されていません...
Sulthan

22
それらが列挙型と呼ばれているのは皮肉ではありませんが、Swiftで列挙するのが非常に面倒です。
チャールトンプロヴァタス

3
@CharltonProvatasもしそれがSwiftの唯一の欠点だったら、私はそれを1日と呼びます。これに対してさまざまな回避策を提供している人の数を見ると、キーボードをかじっているだけです。
qwerty_so 2018

回答:


267

Swift 4.2以降

始まるスイフト4.2(Xcodeの10で)、わずかにプロトコル適合を追加CaseIterableから利益を得ますallCases。このプロトコル準拠を追加するには、どこかに書き込む必要があります。

extension Suit: CaseIterable {}

列挙型が独自のものである場合は、宣言で適合性を直接指定できます。

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

次に、次のコードはすべての可能な値を出力します:

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

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

Swift 3.xまたは4.0をサポートする必要がある場合は、次のコードを追加して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

@DmitryPetukhovお手伝いさせていただきますが、(1)コードの最新バージョンを手に入れましたか?(1か月前に一部のクラッシュが修正されました)および(2)クラッシュを再現できるカスタムタイプのMCVEとXcodeのバージョンを指定してください。
2018

これはデバッグビルドではうまく機能しますが、リリースを作成してTestFlightにアップロードするとすぐにクラッシュします。Appleは何とかこれを取り除いていますか?
ダニエルウッド

1
お使いのバージョンには、CaseIteratorの組み込みバージョンよりも良い点があるようです。別のファイルで定義されている列挙型をあなたのバージョンで拡張できます。拡張機能でallCasesをパブリックにすると、さまざまなフレームワークで定義された列挙型を拡張することもできます。
adamfowlerphoto

1
@Cyber​​Mew明確にするために答えを更新しました。SwiftブックとXcode 10のリリースノートでCaseIterableについて言及しているのは私の回答の後Stringにあり、現在のスタックオーバーフローの質問とは対照的に、列挙型がで裏付けられていない簡略化された例を使用しています。
クール

1
「#if!swift(> = 4.2)」の重要性を強調したいと思います。Swift 4.2より前のコードを記述し、「#if!swift(> = 4.2)」のコードを削除するのを忘れた場合、Xcodeバージョン11.4を使用してテストデバイスでローカルにビルドすると、すべてが正常に動作します。ただし、アプリをアプリストアまたはテストフライトからダウンロードすると、そのコードによってアプリがクラッシュします。この種のバグは、発見またはデバッグが非常に困難です。
Oliver Zhang

524

この投稿はここに関連しています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
}

188
いいですが...列挙の要素を2回入力する必要があります。1回は列挙、もう1回はallValuesです。望むほどエレガントではありません。
Jay Imerman、2014年

2
「しかし」に同意してください...しかし、記事で述べたように、おそらく列挙型は実際にはセットであり、したがって順序付けられていないという問題があるかもしれません...
rougeExciter 2014年

3
Javaでは、コンパイラーがこれを行います。おそらくSwift 2.0もこれを行います。特にJavaの場合、すべての列挙型は、文字列をケース名(Washersなど)として提供する説明(JavaではtoString)メソッドを取得し、ケースのセットが自動的に作成されます。Javaは位置インデックスも提供します。私が言ったように、多分Swift 2.0。
ハワードロバット2014

1
理想的には、c#の実装に似ているEnum.Values(typeof(FooEnum))が、拡張メソッド(マップやリデュースなど)として公開することができます。 FooEnum.values() :: values(EnumType -> [EnumType])
rodrigoelp 2014

1
この記事は、各列挙型の値をユニットテストを使用してallValues配列に含めることについて、最後の方で良い説明をしています。しかし、誰かが要素を追加しているのを見ることができますが、ユニットテストでそれらを強制しないため、最初に戻ってしまい、すべての列挙値がallValuesに保持されていることを確認できません。
DonnaLea 2015

278

iterateEnum()任意のenum型のケースを反復するユーティリティ関数を作成しました。

次に使用例を示します。

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を除く、enum関連するタイプでsが、例数があるとき例だけ指標である2...256、それは同じだUInt8とき、257...65536それはだ、UInt16というように。したがって、unsafeBitcast対応する符号なし整数型からのものである可能性があります。
  • .hashValue 列挙型の値は、ケースのインデックスと同じです。
  • .hashValue無効なインデックスからビットキャストされた列挙値のは0です。

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

20
素晴らしい、そして質問に答える唯一の答え!しかし、うん...それに触れないでください!しかし、努力のために+1!
dotToString 2015年

基本的に同じ方法で機能する私の回答を投稿しました(この回答は後で見ただけです)。Swift 2.0ベータ6と言語の最新機能を使用しています。
Kametrixom 2015

2
Swift 3バージョンは正常に動作します。使用法を少し変更する必要があるだけです:iterateEnum(Suit.self){print(f.rawValue)のfの場合
Gene De Lisa

16
+1これは非常に素晴らしいです。それはまた、私見ですが、Swiftのすべてのメジャーバージョンの変更で大幅に機能が停止することからもわかるように、使用するには賢すぎます。スウィフト3は、ベータ版で出てきた前に、作者の名誉のために、スウィフト3バージョンでは、この答えを取ると、このすべてを学ぶつもりなら...月に行われたwithUnsafePointer withMemoryReboundpointee、スタッフがすべての手段によって、これを使用しています。そうでなければ、私はそれを避けます。
Dan Rosenstark、2016

5
これを追加したいのはSwift 4で壊れていますが、Linux上のみなので、上記のコメントに+1してこれは賢すぎて使用できません。
Andrew Plummer 2017年

130

他のソリューションは機能しますが、それらはすべて、たとえば可能なランクとスートの数、または最初と最後のランクが何であるかを想定しています。確かに、カードのデッキのレイアウトはおそらく予見可能な将来においてあまり変化しないでしょう。ただし、一般に、できるだけ少ない仮定を行うコードを記述する方が適切です。私の解決策:

Suitenumにrawタイプを追加したのでSuit(rawValue:)Suitケースにアクセスするために使用できます。

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

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
            case .Queen:
                return "queen"
            case .King:
                return "king"
            default:
                return String(self.rawValue)
        }
    }
}

カードのcreateDeck()メソッドの実装の下。init(rawValue:)失敗可能な初期化子であり、オプションを返します。両方のwhileステートメントでその値をアンラップしてチェックすることで、ケース数RankSuitケースを想定する必要がなくなります。

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

12
このトピックのさまざまなスレッドで見た絶対的な最高の答え。とてもエレガント。これはInt型の列挙で機能しますが、他の型(文字列、カスタム型など)をどのように反復できるのかと思います。
Jay Imerman、2014年

3
これは間違いなく最良の解決策です。注意すべきことの1つ。本の例では、sdduursmaのように「case Spades = 1」はありません。私は最初これを捕らえませんでした。これは1つのオプションですが、 "var m = 0"を使用することもできます
Joshua Goossen

10
これは、生の値がシーケンシャルであることを前提としています。これが当てはまらない場合、たとえばenumがビットマスクフラグを表す場合、ループは途中で終了します。
ジム

1
このソリューションでは、の定義を変更できることを前提としていますSuit。この例ではできますが、この演習はenums、外部ソースから提供されているかのように、与えられたで作業することを目的としています。
Josh J

1
文句を言いたくないのは、静的メソッドとして呼び出すことはできませんが、最初にカードオブジェクトを作成する必要があることです。
2016年

76

ビットとバイトを偶然見つけて、@ rintaroの回答と非常によく似た作品を後で見つけた拡張機能を作成しました。これは次のように使用されます:

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

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

注目に値するのは、関連付けられた値がなくても列挙型で使用できることです。これは、ケースのない列挙型では機能しないことに注意してください。

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

コード(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が、コンパイラーはそれがなければ文句を言います。


10
この答えは、特に鋳造部分で私の答えよりも優れています:)
rintaro

しかし、これはリトルエンディアン環境でのみ機能すると思いますか?
rintaro 2015

5
Xcode 8ベータ6はこれを再び変更しました!一時的に別のレイアウト互換type.`としてメモリを表示するために「(_へ::容量)withMemoryRebound」使用:私は、次のエラー`「initが」使用不能になってしまう
Vorlon混乱

1
@ConfusedVorlon:@Rintaroによる上記の回答を参照:withUnsafePointerpointee}を置き換えるwithUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } }
Stefan

1
これはXcode 10以降は機能していないようです(Swift 4.2では必要ないことはわかっています)。ただし、Xcode 10でSwift 4(.1)を使用すると、このコードは機能しません(生の値が等しくありません)
benrudhart

26

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
}

2
範囲内で使用した場合の結果の構文(構文は私がenumeratable sans workaroundsで列挙型の場合に実行できることが期待されます)。ありがとう!オペレーターのオーバーロードがsuccessor()以外の場所で採用されている場合(それは魅力的であるように思われます)、強制アンラップが明らかに危険であることは注目に値しますが。また、中置は不要のようです...?
iOSゲーマー

最新のSwift言語仕様を反映するように回答を更新
RndmTsk

適切に定義されたsuccessor()メソッド(最初のオプション)はenum、が関連する型を持つ必要をなくします。+1
nhgrif

1
しかし、このエレガントな答えはString列挙型では機能しませんか?
Ali

ほとんどの「適切な」/ベストプラクティスソリューション!+1 ed
Siu Ching Pong -Asuka Kenji-

18

この問題ははるかに簡単になりました。これが私の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
}

ああ、私は今、私の鉱山はSutean Rutjanalardのものと基本的に同じであることがわかりました。
adazacom、2015

1
実際、私はあなたの実装の方が好きでした。はっきりしていると思います!1票。実際、最も投票された回答はあまりにも賢明であり、将来的には間違いなく破綻するでしょう。あなたは将来的にある程度の安定を約束します。
jvarela 16

17

原則として、列挙型の場合に生の値の割り当てを使用しないことを前提として、この方法でこれを行うことができます。

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

7
これはすばらしいですが、0から始まる連続した整数列挙型でのみ機能します
Robert

@Robert、私のコメントに上記のように:「列挙型のケースに生の値の割り当てを使用しない」
Alfa07

はい-生の値を使用しないでください。また、基になる型をintに設定します。Swiftでは、スーツの例のように列挙型の型は必要ありません。enum ItWontWorkForThisEnum {case a, b, c}
Robert

タプルが列挙型のケースに関連付けられている場合、これはどのように問題に対処しますか?
rougeExciter 14

タプルを列挙型に簡単に関連付けることはできません。
nhgrif 14

13

列挙型に生の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のraw値がある限り)列挙型を作成するときはいつでも、プロトコルに準拠することで列挙型にすることができます。

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

より標準的なCustomStringConvertibleプロトコルへの置き換えsimpleDescriptionを含む最後の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
    }
}

nextIndex ++はswift 3で削除されます。代わりに何を提案しますか-var nextIndex = firstRawValue()return anyGenerator {Self(rawValue:nextIndex ++)}
Avi

理解した。defer {nextIndex + = 1} return AnyGenerator {Self(rawValue:nextIndex)}
Avi

12

更新スウィフト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
        }
    }
}

これは、@ Kametrixomの回答からSwift 2.2に更新されたコードです。

スウィフト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
        }
    }
}

@silvanskyどういう意味ですか?
ale_stro

おっと、申し訳ありませんが、私は再確認し、遊び場のバグがありました:実際のプロジェクトでは、このコードは期待通りに機能します、ありがとう!=)
シルヴァンスキー、

1
素晴らしい解決策!また、最小限の変更でSwift 3で正常に動作します(「AnyGenerator」は「AnyIterator」に名前が変更され、「。memory」は「.pointee」に名前が変更されました)。
フィリップ

9

Swift 5ソリューション:

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

// access cases like this:

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

7

私は自分の.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

Xcode 10と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 }
}

あれを呼べ

print(Filter.allValues)

プリント:

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


古いバージョン

以下のためのenum表現Int

enum Filter: Int {
    case salary
    case experience
    case technology
    case unutilized
    case unutilizedHV

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

次のように呼び出します。

print(Filter.allValues)

プリント:

[0、1、2、3、4]


以下のためのenum表現String

enum Filter: Int {
    case salary
    case experience
    case technology
    case unutilized
    case unutilizedHV

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

extension Filter: CustomStringConvertible {
    var description: String {
        switch self {
        case .salary: return "Salary"
        case .experience: return "Experience"
        case .technology: return "Technology"
        case .unutilized: return "Unutilized"
        case .unutilizedHV: return "Unutilized High Value"
        }
    }
}

あれを呼べ

print(Filter.allValues)

プリント:

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


7

編集: Swift Evolution Proposal SE-0194 Derived Collection of Enum Casesは、この問題の解決策を提案します。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)
}

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

これはどう?


ありがとう、それは私が必要とするように機能します。しかし、マップクロージャで、インデックスではなく名前で値を取得する機会はありますか?
ミハイル

4

このように列挙してみることができます

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]

1
無駄なコードがたくさんあります!これは以下と等価ですstatic var enumerate = [Mercury, Venus, Earth, Mars]投票してほとんどのに比べて基準以下の答えながら、解答stackoverflow.com/a/24137319/1033581
・クール

@Cœurこの回答には、コンパイラを使用してケースを見逃さないことを保証するという重要な利点があります。
dchakarov

あなたが書く場合は、ユーザー・エラーを作成することを可能にする同じ問題を抱えている・クール@、すなわちコンパイラが文句を言わないだろうreturn [Mercury, Venus, Mars]代わりにreturn [Mercury, Venus, Earth, Mars]
dchakarov

@dchakarov私は、明確にするために、答えとして改善を投稿することを決めた:stackoverflow.com/a/50409525/1033581
・クール

@Cœur新しい答えでreturnステートメントをこれに置き換えた場合return [.spades, .hearts, .clubs]、コンパイラは何も言わないので、コードでそれを使用しようとすると、次のようになり[TestApp.Suit.spades, TestApp.Suit.hearts, TestApp.Suit.clubs]ます。列挙型で、ケースを時々追加または削除する必要がある場合、現在の回答は簡潔ではありませんが安全ですが、ソリューションは省略のエラーになりがちです。
dchakarov

4

Swift 3では、基礎となる列挙型にがrawValueある場合、Strideableプロトコルを実装できます。利点は、他のいくつかの提案のように値の配列が作成されないこと、および標準のSwift for forループが機能することです。これにより、優れた構文が作成されます。

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

ああ、ちょうどForwardIndexTypeを置き換えるために探していたもの。今私の反復は使用サイトでよく見えます...ちょうど適切なSwiftyの方法。
Andrew Duncan

4

このソリューションは、可読性と保守性の適切なバランスを実現します。

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

私の意見では、これが最良の解決策です。ほとんどの場合、迅速なコードを見ると、読みやすさはobjcよりも優れていません。しかし、プログラマーがコードの読者にもっと注意を払ったのなら、そうなる可能性があります。例えば彼らの将来の自己、:)
ヴィレーム・クルツ

4

申し訳ありませんが、私の答えは、この投稿をどのように使用する必要があるかを具体的に示したものでした。この質問に遭遇し、列挙内でケースを見つける方法を探している人にとって、これはそれを行う方法です(Swift 2の新機能):

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

// From apple docs: If the raw-value type is specified as String and you don’t assign values to the cases explicitly, each unassigned case is implicitly assigned a string with the same text as the name of that case.

enum Theme: String
    {
    case white, blue, green, lavender, grey
    }

func loadTheme(theme: String)
    {
    // this checks the string against the raw value of each enum case (note that the check could result in a nil value, since it's an optional, which is why we introduce the if/let block
    if let testTheme = Theme(rawValue: theme)
        {
        // testTheme is guaranteed to have an enum value at this point
        self.someOtherFunction(testTheme)
        }
    }

列挙型の列挙について不思議に思う人にとって、すべての列挙値の配列を含む静的なvar / letを含むこのページに示されている答えは正しいです。tvOSの最新のAppleサンプルコードには、まったく同じ手法が含まれています。

そうは言っても、言語にもっと便利なメカニズムを組み込む必要があります(Apple、聞いていますか?)!


3

実験は:実験

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

したがって、メソッドを追加する以外にコードを変更または拡張せずに(そして、まだ教えられていないものを使用せずに)、私はこの解決策を思いつきました:

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

ここに私が両方を反復し、enum1つから複数の値タイプを提供するために使用する方法があります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
数字の1つのフランス語:un、スペイン語:uno、日本語:ichi
数字の2つのフランス語:deux、スペイン語:dos、日本語:ni
数字の3つのフランス語:trois、スペイン語:tres、japanese:san
ナンバー4フランス語:quatre、スペイン語:cuatro、japanese:shi
ナンバー5フランス語:cinq、スペイン語:cinco、日本語:go
ナンバー6フランス語:6、スペイン語: seis、日本語:roku
The number Seven in french:sept、スペイン語:siete、japanese:shichi

合計8件

日本語でsiete:七


更新

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

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

これはハックのようですが、生の値を使用すると、次のようなことができます

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

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

2

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

@Kametrixomの答えと同じように、ここで私は、など、あなたがそのような数として配列のグッズのすべてにアクセスすることができますので、配列を返すことは、より良いAnySequenceを返すよりもだろうと考えています

これが書き直しです:

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

別の解決策:

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

これはSwift 2.0からのかなり古い投稿です。swift 3.0の新しい機能を使用するいくつかの優れたソリューションがここにあります: Swift 3.0の列挙型の反復

そしてこの質問には、(この編集を書いているときにまだリリースされていない)Swift 4.2の新機能を使用するソリューションがあります: Swift列挙のカウントを取得するにはどうすればよいですか?


このスレッドと他のスレッドには多くの優れたソリューションがありますが、それらのいくつかは非常に複雑です。できるだけ簡略化したい。さまざまなニーズで機能する場合と機能しない場合があるソリューションは次のとおりですが、ほとんどの場合はうまく機能すると思います。

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

1
これは、作成した個々の列挙型に固有の多くの作業のように感じられます-この場合、return [Number.One.rawValue、Number.Two.rawValue、...]がきれいではないかわかりません。
スコットオースティン

これはSwift 2.0からのかなり古い投稿です。これで、swift 3.0の新しい機能を使用するいくつかの優れたソリューションがあります。stackoverflow.com/ questions / 41352594 / そして、この質問には、(この編集を書いているため、まだリリースされていない) )スウィフト4.2:stackoverflow.com/questions/27094878/...
アビージャクソン

2

列挙型にはメソッドtoRaw()fromRaw()メソッドがあります。したがって、生の値がの場合Int、最初から最後まで反復できますenum

enum Suit: Int {
    case Spades = 1
    case Hearts, Diamonds, Clubs
    func simpleDescription() -> String {
        switch self {
        case .Spades:
            return "spades"
        case .Hearts:
            return "hearts"
        case .Diamonds:
            return "diamonds"
        case .Clubs:
            return "clubs"
        }
    }
}

for i in Suit.Spades.toRaw()...Suit.Clubs.toRaw() {
    if let covertedSuit = Suit.fromRaw(i) {
        let description = covertedSuit.simpleDescription()
    }
}

1つの落とし穴は、simpleDescriptionメソッドを実行する前にオプションの値をテストする必要があるため、convertedSuit最初に値を設定し、次に定数をconvertedSuit.simpleDescription()


2
元の質問は、IntではなくString型の列挙型に関するものでした
cynistersix '11 / 11/14

2

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

ソリューション全体をエコーするのではなく.、caseステートメントの後のどこかにあるenum に追加したコードを次に示します(Suitenumも同様です)。

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

そして、デッキを文字列の配列として構築するために使用したループ。(問題の定義には、デッキの構成方法は記載されていませんでした。)

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.first代わりに言いたいですRank.Ace.first。(任意の要素で)機能しますが、醜いです。誰かがそれを列挙型レベルに上げる方法を示すことができますか?

そしてそれを機能させるために、私createDeckはカード構造体からメソッドを持ち上げました。その構造体から[String]配列を返す方法を理解できなかったので、そのようなメソッドを配置するのは悪い場所のようです。


2

私はすべての値の配列を返す計算されたプロパティを使用してそれを行いました(この投稿http://natecook.com/blog/2014/10/loopy-random-enum-ideas/に感謝します)。ただし、これはint raw値も使用しますが、列挙のすべてのメンバーを個別のプロパティで繰り返す必要はありません。

UPDATE Xcode 6.1 rawValueでは、enumメンバーをを使用して取得する方法が少し変更されたため、リストを修正しました。最初に間違った小さなエラーも修正しましたrawValue

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

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

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


Countケースを追加すると、完全なswitch実装とCaseIterable適合性が失われます。
クール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.