स्ट्रिंग प्रकार के साथ एक एनुम की गणना कैसे करें?


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

उदाहरण के लिए, मैं कुछ कैसे कर सकता हूं:

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

परिणाम उदाहरण:

♠
♥
♦
♣

आप किस उदाहरण में नहीं जानते हैं?
mtbennett

आप सही हैं, इस मामले में यह स्ट्रिंग प्रकार है।
ल्यूसिन

स्विफ्ट में अभी तक कोई प्रतिबिंब नहीं ...
सुल्तान

22
क्या यह विडंबना नहीं है कि उन्हें एन्यूमरेशन्स कहा जाता है, लेकिन वे स्विफ्ट में बहुत अधिक कष्टप्रद हैं?
चार्लटन प्रोवेट्स 21

3
@CharltonProvatas यदि स्विफ्ट में एकमात्र दोष था, तो मैं इसे एक दिन कहूंगा। यह देखते हुए कि कितने लोग इसके लिए अलग-अलग वर्कअराउंड की पेशकश करते हैं , मैं सिर्फ अपने कीबोर्ड को देख रहा हूं।
qwerty_so

जवाबों:


266

स्विफ्ट 4.2+

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

पहले स्विफ्ट संस्करणों के साथ संगतता (3.x और 4.x)

यदि आपको स्विफ्ट 3.x या 4.0 का समर्थन करने की आवश्यकता है, तो आप निम्नलिखित कोड जोड़कर स्विफ्ट 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) क्या आपको यकीन है कि आपको कोड का नवीनतम संस्करण मिला है? (कुछ दुर्घटना एक महीने पहले तय की गई थी) और (2) कृपया अपने कस्टम प्रकार का एक MCVE दें जो एक दुर्घटना को पुन: उत्पन्न कर सकता है, और आपका Xcode का संस्करण।
करूर

डिबग बिल्ड के लिए यह मेरे लिए ठीक काम करता है, लेकिन जैसे ही मैं एक रिलीज बनाता हूं और टेस्टफलाइट पर अपलोड करता है, यह क्रैश हो जाता है। क्या Apple किसी तरह से यह छीन रहा है?
डैनियल वुड

1
ऐसा लगता है कि आपके संस्करण में CaseIterator के इनबिल्ट संस्करण पर एक सकारात्मक है। मैं आपके संस्करण के साथ किसी अन्य फ़ाइल में परिभाषित की गई दुश्मनी को बढ़ा सकता हूं। यदि आप एक्सटेंशन को सार्वजनिक करते हैं तो आप विभिन्न फ्रेमवर्क में परिभाषित एनमों को भी बढ़ा सकते हैं।
adamfowlerphoto

1
@CyberMew मैंने इसे स्पष्ट करने के लिए उत्तर अपडेट किया है। स्विफ्ट बुक और Xcode 10 के रिलीज़ नोटों में CaseIterable के उल्लेख मेरे उत्तर से पीछे हैं और उन्होंने सरलीकृत उदाहरणों का उपयोग किया जहां Stringवर्तमान स्टैक ओवरफ्लो प्रश्न के विपरीत, एनम के साथ समर्थित नहीं है ।
C --ur

1
मैं "# अगर! स्विफ्ट (> = 4.2)" के महत्व पर जोर देना चाहूंगा। यदि आपने अपना कोड ४.२ से पहले लिखा है और आप कोड बोले को दूर करना भूल गए हैं तो "# अगर! स्विफ्ट (> = ४.२)", जब आप अपने टेस्ट डिवाइस पर स्थानीय रूप से बनाने के लिए Xcode संस्करण 11.4 का उपयोग करते हैं, तो सबकुछ ठीक हो जाएगा। लेकिन जब आपका ऐप ऐप स्टोर या टेस्ट फ्लाइट से डाउनलोड होता है, तो कोड का टुकड़ा आपके ऐप को क्रैश कर देगा। उस तरह का बग स्पॉट या डीबग करना बहुत कठिन है।
ओलिवर झांग

524

यह पोस्ट यहाँ प्रासंगिक है https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-tift

अनिवार्य रूप से प्रस्तावित समाधान है

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
"लेकिन" ... से सहमत हैं, लेकिन जैसा कि लेख में कहा गया है कि शायद एक मुद्दा है कि एक एनम वास्तव में एक सेट है और इसलिए अनियंत्रित है ... आपका मन करता है ... आदेश में परिभाषित मामले खराब शुरुआत नहीं होंगे!
rougeExciter

3
जावा में कंपाइलर आपके लिए ऐसा करता है, हो सकता है कि स्विफ्ट 2.0 भी ऐसा करे। विशेष रूप से जावा में सभी एनमों को एक विवरण मिलता है (जावा में स्ट्रींग) विधि जो स्ट्रिंग को केस के नाम (वाशर, ...) के रूप में देता है और मामलों का एक सेट स्वचालित रूप से बनाया जाता है। जावा आपको स्थितिगत अनुक्रमण भी देता है। जैसा कि मैंने कहा, शायद स्विफ्ट 2.0।
हावर्ड लोवेट

1
आदर्श रूप से आपके पास c # कार्यान्वयन के समान कुछ होगा जिसमें आप कर सकते हैं Enum.Values(typeof(FooEnum))लेकिन एक विस्तार विधि (जैसे नक्शा या कम) के रूप में उजागर किया जा सकता है । FooEnum.values() :: values(EnumType -> [EnumType])
रॉडरिगोल्प

1
एक इकाई परीक्षण के साथ ऑलव्यूअल ऐरे में प्रत्येक एनुम मान बनाने के बारे में लेख अंत में एक अच्छा बिंदु बनाता है। हालांकि, मैं अभी भी किसी को अधिक तत्व जोड़ते हुए देख सकता हूं, लेकिन उन्हें यूनिट टेस्ट में लागू नहीं कर रहा हूं जो अभी भी शुरुआत में हमें वापस छोड़ देता है, यह सुनिश्चित करने के लिए नहीं जानता कि सभी एन्यूअल वैल्यू ऑलवैल्यू में रखे गए हैं।
डोनालिया

278

मैंने iterateEnum()मनमाने ढंग से मामलों की पुनरावृति के लिए एक उपयोगिता कार्य कियाenum प्रकार के ।

यहाँ उदाहरण का उपयोग किया गया है:

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

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

कौन से आउटपुट:

♠
♥
♦
♣

लेकिन, यह केवल डिबग या टेस्ट के लिए है उद्देश्यों के लिए है: यह कई अनिर्दिष्ट स्विफ्ट 1.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मामलों की एक सूची है, जब मामलों की गिनती होती है 2...256, तो यह समान है UInt8, जब 257...65536, यह UInt16और इसी तरह। तो, यह हो सकता हैunsafeBitcast संबंधित अहस्ताक्षरित पूर्णांक प्रकारों से है।
  • .hashValue enum मान मामले के सूचकांक के रूप में ही है।
  • .hashValueसे bitcasted enum के मूल्यों अवैध सूचकांक है 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
    }
}

स्विफ्ट 3 के लिए संशोधित:

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

मैंने बस अपना उत्तर पोस्ट किया है जो मूल रूप से उसी तरह से काम करता है (केवल बाद में इस उत्तर को देखा)। इसमें स्विफ्ट 2.0 बीटा 6 और भाषा की आधुनिक विशेषताओं का उपयोग किया गया है।
कामेट्रिक्सम

2
स्विफ्ट 3 संस्करण अच्छा काम करता है। बस उपयोग को थोड़ा संशोधित करने की आवश्यकता है: iterateEnum (Suit.self) में f के लिए {प्रिंट (f.rawValue)}
जीन डी लिसा

16
+1 यह काफी शानदार है। यह भी है, IMHO, उपयोग करने के लिए बहुत चालाक है, क्योंकि इसके द्वारा हर प्रमुख स्विफ्ट संस्करण परिवर्तन में महत्वपूर्ण रूप से तोड़ दिया गया है। लेखक के क्रेडिट के लिए, स्विफ्ट 3 संस्करण एक महीने पहले किया गया था जब स्विफ्ट 3 बीटा से बाहर आया था ... यदि आप इस उत्तर को लेने जा रहे हैं और यह सब withUnsafePointer withMemoryReboundऔर pointeeसामान सीखना चाहते हैं , तो इसका उपयोग सभी तरीकों से करें। नहीं तो मैं इससे बचता।
डैन रोसेनस्टार्क

5
मैं बस यह जोड़ना चाहता हूं कि यह अब स्विफ्ट 4 में टूट गया है, लेकिन केवल लिनक्स पर, इसलिए उपरोक्त टिप्पणियों के लिए +1 यह उपयोग करने के लिए बहुत चालाक है।
एंड्रयू प्लमर

130

अन्य समाधान काम करते हैं लेकिन वे सभी उदाहरण के लिए संभव रैंकों और सूटों की संख्या या पहले और अंतिम रैंक क्या हो सकते हैं, की धारणा बनाते हैं। यह सच है, ताश के पत्तों की एक डेक शायद भविष्य के भविष्य में ज्यादा बदलने वाली नहीं है। सामान्य तौर पर, हालांकि, यह कोड लिखना है जो संभव के रूप में कम धारणा बनाता है। मेरा समाधान:

मैंने एनम में एक कच्चा प्रकार जोड़ा है Suit, इसलिए मैं मामलों का उपयोग 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:)एक प्रारंभिक आरम्भिक है और एक वैकल्पिक रिटर्न देता है। बयानों के दौरान अपने मूल्य को उजागर और जाँचने से, संख्या 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()

12
निरपेक्ष सबसे अच्छा जवाब मैंने इस विषय पर विभिन्न थ्रेड्स पर देखा है। बहुत खूबसूरत। यह इंट प्रकार एन्यूमरेशन्स के साथ काम करता है, लेकिन मुझे आश्चर्य है कि कोई अन्य प्रकार (स्ट्रिंग, कस्टम प्रकार, आदि) के माध्यम से कैसे पुनरावृति कर सकता है।
जे इमरमान

3
यह निश्चित रूप से सबसे अच्छा समाधान है। एक बात ध्यान दें। पुस्तक में उदाहरण में यह "केस हुकुम = 1" नहीं है जैसा कि sdduursma के पास है। मैंने इसे पहले नहीं पकड़ा था। यह एक विकल्प है, या आप बस "var m = 0" का उपयोग कर सकते हैं
जोशुआ गूसेन

10
यह धारणा बनाता है कि कच्चे मूल्य अनुक्रमिक हैं। जब यह सच नहीं है, उदाहरण के लिए जब एनम बिट मास्क झंडे का प्रतिनिधित्व करता है, तो लूप समय से पहले निकल जाता है।
जिम

1
यह समाधान मानता है कि आप की परिभाषा को संशोधित कर सकते हैं Suit। आप इस उदाहरण में देख सकते हैं, लेकिन अभ्यास का मतलब था कि आपको काम करने के लिए enumsआपको दिया गया था जैसे कि वे एक बाहरी स्रोत से थे।
जोश जे

1
केवल एक चीज जिसकी मैं शिकायत करना चाहता हूं, वह यह है कि मैं इसे स्टैटिक विधि नहीं कह सकता, लेकिन पहले एक कार्ड ऑब्जेक्ट बनाना होगा।
QED

76

मैं बिट्स और बाइट्स में चारों ओर ठोकर खाई और एक विस्तार बनाया जो मुझे बाद में पता चला कि यह @rintaro के उत्तर के समान है । यह इस तरह प्रयोग किया जाता है:

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

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

उल्लेखनीय बात यह है कि संबंधित मूल्यों के बिना यह किसी भी Enum पर प्रयोग करने योग्य है। ध्यान दें कि यह उन मामलों के लिए काम नहीं करता जिनके पास कोई मामला नहीं है।

@Rintaro के उत्तर के साथ के रूप में , यह कोड एक एनम के अंतर्निहित प्रतिनिधित्व का उपयोग करता है। यह प्रतिनिधित्व प्रलेखित नहीं है और भविष्य में बदल सकता है, जो इसे तोड़ देगा। मैं उत्पादन में इसके उपयोग की अनुशंसा नहीं करता।

कोड (स्विफ्ट 2.2, एक्सकोड 7.3.1, एक्सकोड 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
            }
        }
    }
}

कोड (स्विफ्ट 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
यह जवाब मेरे जवाब से भी बेहतर है, खासकर कास्टिंग पार्ट में :)
रेंटारो

लेकिन मुझे लगता है कि यह केवल एंडियन पर्यावरण पर काम करता है?
रिंटारो सेप

5
Xcode 8 बीटा 6 ने इसे फिर से बदल दिया है! मैं निम्न त्रुटि ` 'init' अनुपलब्ध है: उपयोग 'withMemoryRebound (करने के लिए: क्षमता: _)' के लिए अस्थायी रूप से एक और लेआउट संगत type.` के रूप में स्मृति देखने
Vorlon उलझन

1
बदलें: @ConfusedVorlon: @Rintaro से ऊपर उत्तर देखें withUnsafePointer... pointee}द्वाराwithUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } }
स्टीफन

1
ऐसा लगता है कि अब Xcode 10. के रूप में काम नहीं कर रहा है (मुझे पता है कि यह Swift 4.2 के साथ आवश्यक नहीं होगा) लेकिन Xcode 10 में
ift

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
मुझे लगता है कि यह सवाल का सबसे "उचित" जवाब है, यहां तक ​​कि सबसे "सुरुचिपूर्ण" (अतिरिक्त कोड आवश्यक विज़-ए-विज़ अन्य विकल्प यहां समझ में आता है) परिणामी सिंटैक्स दिया गया जब एक सीमा के भीतर उपयोग किया जाता है (सिंटैक्स मैं क्या हूं उम्मीद है कि अगर enumseratable संस workarounds जहां) करने में सक्षम हो जाएगा। धन्यवाद! हालांकि यह ध्यान देने योग्य है कि यदि ऑपरेटर ओवरलोडिंग को उत्तराधिकारी () के अलावा कहीं और नियोजित किया जाता है (जो लुभावना लगता है) तो जाहिर है कि जबरन ओवररैपिंग खतरनाक है। इसके अलावा, इन्फिक्स अनावश्यक लगता है ...?
iOS गेमर

नवीनतम स्विफ्ट भाषा विनिर्देशों को प्रतिबिंबित करने के लिए अपडेट किया गया उत्तर
RndmTsk

एक ठीक से परिभाषित successor()विधि (पहला विकल्प) enumएक संबद्ध प्रकार की आवश्यकता को समाप्त कर देगा । +1
nhgrif

1
लेकिन यह खूबसूरत जवाब स्ट्रिंग एनम के लिए काम नहीं करेगा?
अली

सबसे "उचित" / सर्वोत्तम अभ्यास समाधान! + 1-ईडी
सिउ चिंग पोंग -आसुका केंजी-

18

यह समस्या अब बहुत आसान है। यहाँ मेरा स्विफ्ट 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:

मैं इस समाधान को पसंद करता हूं जिसे मैंने स्विफ्ट में " सूची समझ " के बाद एक साथ रखा था

यह स्ट्रिंग्स के बजाय इंट रॉ का उपयोग करता है लेकिन यह दो बार टाइप करने से बचता है, यह सीमाओं को अनुकूलित करने की अनुमति देता है, और हार्ड कोड कच्चे मूल्यों को नहीं देता है।

यह मेरे मूल समाधान का एक स्विफ्ट 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
}

ओह, अब मैं देख रहा हूं कि मेरा मूल रूप से सुत रतनजनार्ड के जैसा ही है।
adazacom

1
दरअसल, मुझे आपका कार्यान्वयन बेहतर लगा। मुझे लगता है कि यह स्पष्ट है! 1 अपवोट। वास्तव में सबसे अधिक मतदान के जवाब बहुत चालाक हैं और भविष्य में सबसे निश्चित रूप से टूटेंगे। आपका भविष्य में कुछ स्थिरता का वादा करता है।
जवारेला

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
रॉबर्ट

@ रोबर्ट, जैसा कि मेरी टिप्पणी में कहा गया है: "आप
एनम

हां - कच्चे मानों का उपयोग न करें, साथ ही साथ अंतर्निहित प्रकार को अंतर करने के लिए सेट करें। स्विफ्ट में आपको एक उदाहरण के लिए एक प्रकार की आवश्यकता नहीं है जैसे सूट उदाहरण में। enum ItWontWorkForThisEnum {case a, b, c}
रॉबर्ट

इस मुद्दे को कैसे पता चलेगा कि अगर कोई टुकड़ी गणना मामले से जुड़ी है?
rougeExciter

आप एक ट्यूल को बहुत आसानी से एक Enum में नहीं जोड़ सकते हैं।
nhgrif 15

13

यदि आप Enum को एक Int 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())

हालाँकि, यह काफी सामान्य पैटर्न की तरह दिखता है, क्या यह अच्छा नहीं होगा यदि हम किसी भी प्रकार के एनुम प्रकार को केवल एक प्रोटोकॉल के अनुरूप बना सकते हैं? अच्छी तरह से स्विफ्ट 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 }
}

अब किसी भी समय आप एक एनम बनाते हैं (इसलिए जब तक इसका इंट रॉ वैल्यू है), आप इसे प्रोटोकॉल के अनुरूप बना सकते हैं:

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

यदि आपके enum मान 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 प्रोटोकॉल , इस तरह दिखेगा:

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

स्विफ्ट 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 ++ को स्विफ्ट में हटा दिया जाएगा। 3. आप प्रतिस्थापन के रूप में क्या सुझाव देते हैं - var nextIndex = firstRawValue () रिटर्न AnyGenerator {सेल्फ (rawValue: nextIndex ++)}
Avi

पता लगा लिया। defer {NextIndex + = 1} 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
        }
    }
}

यह स्विफ्ट 2.2 फॉर्म का कोड है @ Kametrixom के उत्तर

के लिए स्विफ्ट 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
महान समाधान! इसके अलावा, स्विफ्ट 3 पर न्यूनतम परिवर्तन ('AnyGenerator' का नाम बदलकर 'AnyIterator' और '.memory' का नाम बदलकर '.pointee') ठीक रखने का काम करता है।
फिलिप

9

स्विफ्ट 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

स्विफ्ट 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)

प्रिंटों:

["वेतन", "अनुभव", "प्रौद्योगिकी", "अनुपयोगी", "अप्रयुक्त उच्च मूल्य"]


पुराने संस्करण

के लिए 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)

प्रिंटों:

[०, १, २, ३, ४]


के लिए 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

संपादित करें: स्विफ्ट विकास प्रस्ताव एसई 0194 Enum मामले का संग्रह व्युत्पन्न एक स्तर अध्यक्षता में प्रस्ताव समाधान इस समस्या के लिए। हम इसे स्विफ्ट 4.2 और नए में देखते हैं। प्रस्ताव कुछ कार्यदशाओं की ओर भी संकेत करता है जो यहाँ पहले से वर्णित कुछ के समान हैं लेकिन फिर भी यह देखना दिलचस्प हो सकता है।

मैं अपनी मूल पोस्ट को पूर्णता के लिए भी रखूंगा।


यह स्विफ्ट 3 के लिए अनुकूलित @ Peymmankh के उत्तर पर आधारित एक और दृष्टिकोण है ।

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

@ इस जवाब से यह सुनिश्चित करने के लिए संकलक का उपयोग करने का महत्वपूर्ण लाभ है कि आप किसी मामले को याद नहीं करेंगे।
ढाचक्रोव

@ कोयूर आप एक उपयोगकर्ता त्रुटि बनाने के लिए अनुमति देने का एक ही समस्या है, यानी संकलक शिकायत नहीं होगा यदि आप लिखना return [Mercury, Venus, Mars]के बजायreturn [Mercury, Venus, Earth, Mars]
dchakarov

@dchakarov मैंने स्पष्टता के लिए उत्तर के रूप में सुधार पोस्ट करने का फैसला किया: stackoverflow.com/a/50409525/1033581
Cœur

@ C @ur यदि आपके नए उत्तर में आप रिटर्न स्टेटमेंट को इस return [.spades, .hearts, .clubs]से बदल देते हैं , तो कंपाइलर एक बात नहीं कहेगा और फिर जब आप इसे कोड में उपयोग करने का प्रयास करेंगे, तो आपको मिलेगा [TestApp.Suit.spades, TestApp.Suit.hearts, TestApp.Suit.clubs]- यह मेरी बात थी - कि अगर आप किसी बड़े के साथ काम कर रहे हैं enum और आपको समय-समय पर मामलों को जोड़ना या निकालना होगा, आपका समाधान चूक की त्रुटियों से ग्रस्त है जबकि वर्तमान उत्तर, जबकि संक्षिप्त नहीं है, अधिक सुरक्षित है।
डचाकारोव

4

स्विफ्ट 3 में, जब अंतर्निहित एनम है rawValue, तो आप Strideableप्रोटोकॉल को लागू कर सकते हैं । लाभ यह है कि मूल्यों के किसी भी सरणियों को कुछ अन्य सुझावों की तरह नहीं बनाया जाता है और "लूप कार्यों में मानक स्विफ्ट" के लिए, जो एक अच्छा वाक्यविन्यास बनाता है।

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

यह समाधान पठनीयता और स्थिरता का सही संतुलन बनाता है।

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

क्षमा करें, मेरा उत्तर इस बात के लिए विशिष्ट था कि मैंने इस पोस्ट का उपयोग किस तरह से करने की आवश्यकता है। जो लोग इस प्रश्न पर ठोकर खाते हैं, उनके लिए एक एनम के भीतर मामला खोजने का तरीका ढूंढना , यह ऐसा करने का तरीका है (स्विफ्ट 2 में नया):

संपादित करें: लोअरकेस कैमलकेस अब स्विफ्ट 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)
        }
    }

किसी एनुम पर एनुमरेटिंग के बारे में सोच रहे लोगों के लिए, इस पेज पर दिए गए उत्तर जिसमें स्टैटिक वर्जन / लेट होता है, जिसमें सभी एनम वैल्यूज की एक सरणी होती है, सही हैं। TVOS के लिए नवीनतम Apple उदाहरण कोड में यह सटीक तकनीक है।

कहा जा रहा है, उन्हें भाषा में एक अधिक सुविधाजनक तंत्र का निर्माण करना चाहिए (Apple, क्या आप सुन रहे हैं?)।


3

प्रयोग था: विशेषज्ञ

कार्ड के लिए एक विधि जोड़ें जो रैंक और सूट के प्रत्येक संयोजन के एक कार्ड के साथ कार्ड का एक पूर्ण डेक बनाता है।

तो विधि को जोड़ने के अलावा दिए गए कोड को संशोधित करने या बढ़ाने के बिना (और सामान का उपयोग किए बिना जो अभी तक सिखाया नहीं गया है), मैं इस समाधान के साथ आया हूं:

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

यहाँ एक तरीका है जो मैं दोनों को पुनरावृत्त करने के लिए उपयोग करता हूं enumऔर एक से कई मान प्रकार प्रदान करता हूं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"))")

यह आउटपुट है:

फ्रेंच में जीरो नंबर: ज़ीरो, स्पेनिश: सेरो, जापानी:
फ्रेंच में नंबर एक: संयुक्त राष्ट्र, स्पेनिश: यूनो, जापानी: ichi
फ्रेंच में नंबर दो: ड्यूक्स, स्पेनिश: डॉस, जापानी: एनआई
नंबर तीन : trois, स्पेनिश: tres, जापानी: san
फ्रेंच में नंबर चार: quatre, स्पेनिश: cuatro, जापानी: shi
नंबर पाँच में फ्रेंच: Cinq, स्पेनिश: Cinco, जापानी: जाने
नंबर छह में फ्रेंच: छह, स्पेनिश: स्पेनिश seis, जापानी: roku
फ्रेंच में सात नंबर: sept, स्पेनिश: siete, जापानी: shichi

कुल 8 मामले

जापानी में siete: शिची


अपडेट करें

मैंने हाल ही में एन्यूमरेशन को संभालने के लिए एक प्रोटोकॉल बनाया। प्रोटोकॉल के लिए एक इंट कच्चे मान के साथ एक एनम की आवश्यकता होती है:

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 उत्तर के रूप में मेरा मानना ​​है कि किसी भी सरणी को लौटाने से बेहतर होगा कि आप किसी भी तरह की असेंसेंस लौटाएं, क्योंकि आपके पास एरे की सभी अच्छाइयों जैसे कि गिनती, आदि तक पहुंच हो सकती है।

यहाँ फिर से लिखना है:

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

यह एक बहुत पुरानी पोस्ट है, स्विफ्ट 2.0 से। अब यहां कुछ बेहतर समाधान हैं जो स्विफ्ट 3.0 की नई सुविधाओं का उपयोग करते हैं: स्विफ्ट 3.0 में एक एनम के माध्यम से Iterating

और इस सवाल पर एक समाधान है जो एक नई सुविधा का उपयोग करता है (अभी तक जारी नहीं है क्योंकि मैं यह संपादन लिखता हूं) स्विफ्ट 4.2: मैं स्विफ्ट एनम की गिनती कैसे प्राप्त करूं?


इस धागे में बहुत सारे अच्छे समाधान हैं और अन्य हालांकि उनमें से कुछ बहुत जटिल हैं। मुझे यथासंभव सरल बनाना पसंद है। यहाँ एक समाधान है जो विभिन्न आवश्यकताओं के लिए काम कर सकता है या नहीं कर सकता है लेकिन मुझे लगता है कि यह ज्यादातर मामलों में अच्छी तरह से काम करता है:

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
ऐसा लगता है कि आपके द्वारा बनाए गए व्यक्तिगत एनम के लिए बहुत सारे काम की तरह है - मुझे यकीन नहीं है कि वापसी [Number.One.rawValue, Number.Two.rawValue, ...] इस मामले में क्लीनर नहीं है ।
स्कॉट ऑस्टिन

यह एक बहुत पुरानी पोस्ट है, स्विफ्ट 2.0 से। अब कुछ बेहतर समाधान यहां दिए गए हैं जो स्विफ्ट 3.0 की नई सुविधाओं का उपयोग करते हैं: stackoverflow.com/questions/41352594/… और इस सवाल पर एक समाधान है जो एक नई सुविधा का उपयोग करता है (अभी तक जारी नहीं हुआ है क्योंकि मैं इसे संपादित करता हूं। ) स्विफ्ट ४.२: stackoverflow.com/questions/27094878/…
अभय जैक्सन

2

Enums है 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()
    }
}

एक गेटा यह है कि आपको simpleDescriptionविधि को चलाने से पहले वैकल्पिक मूल्यों के लिए परीक्षण करने की आवश्यकता है , इसलिए हम convertedSuitपहले अपने मूल्य पर सेट होते हैं और फिर एक स्थिरांक सेट करते हैंconvertedSuit.simpleDescription()


2
मूल प्रश्न एक स्ट्रिंग प्रकार के बारे में था जो
इंटम

2

यहाँ मेरा सुझाया दृष्टिकोण है। यह पूरी तरह से संतोषजनक नहीं है (मैं स्विफ्ट और ओओपी के लिए बहुत नया हूं!) लेकिन शायद कोई इसे परिष्कृत कर सकता है। विचार यह है कि प्रत्येक एनुम को अपनी रेंज जानकारी .firstऔर .lastगुणों के रूप में प्रदान करना है । यह प्रत्येक एनुम में कोड की सिर्फ दो पंक्तियाँ जोड़ता है: अभी भी थोड़ा कठिन-कोडित है, लेकिन कम से कम यह पूरे सेट की नकल नहीं कर रहा है। यह Suitएनुम को एक इंट की तरह संशोधित करने की आवश्यकता हैRank है, एनुम अनटाइप के बजाय एनुम है।

पूरे समाधान को प्रतिध्वनित करने के बजाय, यहाँ कोड को मैंने .एनुम में जोड़ा है , कहीं केस स्टेटमेंट के बाद ( Suitएनम समान है):

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
}

यह असंतोषजनक है क्योंकि गुण ईनम के बजाय एक तत्व से जुड़े हैं। लेकिन यह 'छोरों' के लिए स्पष्टता जोड़ता है। मैं Rank.firstइसके बजाय कहना चाहूंगाRank.Ace.first । यह काम करता है (किसी भी तत्व के साथ), लेकिन यह बदसूरत है। क्या कोई दिखा सकता है कि कैसे उसे एनम स्तर तक ऊंचा किया जाए?

और इसे काम करने के लिए, मैंने createDeckकार्ड संरचना से विधि को हटा दिया । मैं यह पता नहीं लगा सका कि कैसे [स्ट्रिंग] एरे को उस संरचना से लौटाया गया है, और ऐसा तरीका वैसे भी डालने के लिए एक बुरा स्थान है।


2

मैंने यह गणना की गई संपत्ति का उपयोग करते हुए किया, जो सभी मूल्यों की सरणी देता है (इस पोस्ट के लिए धन्यवाद http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ )। हालाँकि, यह इंट-रॉ-वैल्यूज़ का भी उपयोग करता है, लेकिन मुझे अलग-अलग प्रॉपर्टी में एन्यूमरेशन के सभी सदस्यों को दोहराने की आवश्यकता नहीं है।

UPDATE Xcode 6.1 ने एनुम सदस्य का उपयोग करने के तरीके को थोड़ा बदल दिया rawValue, इसलिए मैंने लिस्टिंग को निर्धारित किया। पहले गलत के साथ छोटी त्रुटि भी तय की 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अनुरूपता ।
कोयूर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.