एक सरणी के रूप में सभी एनम मान कैसे प्राप्त करें


99

मेरे पास निम्नलिखित एनम है।

enum EstimateItemStatus: Printable {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending: return "Pending"
        case .OnHold: return "On Hold"
        case .Done: return "Done"
        }
    }

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

मुझे स्ट्रिंग्स की एक सरणी के रूप में सभी कच्चे मूल्यों को प्राप्त करने की आवश्यकता है (जैसे कि ["Pending", "On Hold", "Done"])।

मैंने इस विधि को एनम में जोड़ा।

func toArray() -> [String] {
    var n = 1
    return Array(
        GeneratorOf<EstimateItemStatus> {
            return EstimateItemStatus(id: n++)!.description
        }
    )
}

लेकिन मुझे निम्नलिखित त्रुटि मिल रही है।

'जेनरेटरऑफ' टाइप के लिए एक इनिशियलाइज़र नहीं खोज सकता है जो टाइप की एक तर्क सूची को स्वीकार करता है '() -> _')

क्या ऐसा करने का एक आसान, बेहतर या अधिक सुरुचिपूर्ण तरीका है?


2
आप सरणी को लेट एरे की तरह बना सकते हैं: [एस्टीमेटेमस्टैटस] = [.Pending, .Onhold, .Done]
क्रिस्टीजन डेलिवुक

1
@KristijanDelivuk मैं इस कार्यक्षमता को enum में जोड़ना चाहता हूं। अगर मुझे कभी एनम के लिए एक और मूल्य जोड़ना है तो मुझे कोडबॉसेस के अन्य स्थानों में हर जगह इसे जोड़ने की ज़रूरत नहीं है।
Isuru


मैं एक जवाब आप उल्लेख कर सकते हैं यहां के लिए है stackoverflow.com/a/48960126/5372480
MSimic

जवाबों:


146

स्विफ्ट 4.2 (एक्सकोड 10) और बाद के लिए

एक CaseIterableप्रोटोकॉल है:

enum EstimateItemStatus: String, CaseIterable {
    case pending = "Pending"
    case onHold = "OnHold"
    case done = "Done"

    init?(id : Int) {
        switch id {
        case 1: self = .pending
        case 2: self = .onHold
        case 3: self = .done
        default: return nil
        }
    }
}

for value in EstimateItemStatus.allCases {
    print(value)
}

स्विफ्ट के लिए <4.2

नहीं, आप enumइसमें शामिल नहीं कर सकते हैं कि इसमें क्या मूल्य हैं। इस लेख को देखें । आपको एक सरणी को परिभाषित करना होगा जो आपके पास सभी मूल्यों को सूचीबद्ध करता है। फ्रैंक वाल्बेना के समाधान को " एक सरणी के रूप में सभी एनम मान कैसे प्राप्त करें " में भी देखें।

enum EstimateItemStatus: String {
    case Pending = "Pending"
    case OnHold = "OnHold"
    case Done = "Done"

    static let allValues = [Pending, OnHold, Done]

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

for value in EstimateItemStatus.allValues {
    print(value)
}

इस उत्तर को देखें: स्विफ्ट 3 कोड सहित stackoverflow.com/a/28341290/8047
दान रोसेनस्टार्क

3
AllValues ​​भाग के लिए अपवोटिंग, लेकिन सुनिश्चित नहीं है कि एक Enum के बारे में क्या महसूस करना है String लेकिन Int के साथ initialized।
टायरसन

पहला लिंक टूट गया है, लेकिन अभी अपवादों पर देखा जा रहा है
द टिन मैन

39

स्विफ्ट 4.2 एक नए प्रोटोकॉल का नाम देता हैCaseIterable

enum Fruit : CaseIterable {
    case apple , apricot , orange, lemon
}

जब आप इसके अनुरूप होते हैं, तो आप enumइस तरह के मामलों से एक सरणी प्राप्त कर सकते हैं

for fruit in Fruit.allCases {
    print("I like eating \(fruit).")
}

26

Enum करने के लिए CaseIterable प्रोटोकॉल जोड़ें :

enum EstimateItemStatus: String, CaseIterable {
    case pending = "Pending"
    case onHold = "OnHold"
    case done = "Done"
}

उपयोग:

let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue }
//["Pending", "OnHold", "Done"]

17

एक और तरीका है कि कम से कम संकलन समय पर सुरक्षित है:

enum MyEnum {
    case case1
    case case2
    case case3
}

extension MyEnum {
    static var allValues: [MyEnum] {
        var allValues: [MyEnum] = []
        switch (MyEnum.case1) {
        case .case1: allValues.append(.case1); fallthrough
        case .case2: allValues.append(.case2); fallthrough
        case .case3: allValues.append(.case3)
        }
        return allValues
    }
}

ध्यान दें कि यह किसी भी enum प्रकार (RawRepresentable या नहीं) के लिए काम करता है और यह भी कि यदि आप एक नया मामला जोड़ते हैं तो आपको एक कंपाइलर त्रुटि मिलेगी जो कि अच्छी है क्योंकि आपको यह अप टू डेट करने के लिए मजबूर करेगी।


1
अपरंपरागत, लेकिन यह काम करता है और यह आपको चेतावनी देता है यदि आप एनम मामलों को संशोधित करते हैं। चतुर समाधान!
चक कृत्सिंगर

12

मुझे यह कोड कहीं मिला:

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

उपयोग:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

YourEnum से मामलों की वापसी सूची


एक महान समाधान की तरह लगता है, लेकिन स्विफ्ट 4 पर काफी कुछ संकलित त्रुटियाँ हैं
Isuru

1
"कहीं" हो सकता है: theswiftdev.com/2017/10/12/swift-enum-all-val- (दूसरों के बीच?)। ब्लॉगर CoreKit को श्रेय देता है
अमिताभ

5
यह XCode 10 (स्विफ्ट-संस्करण की परवाह किए बिना) टूट जाता है क्योंकि एक एनम के हैशवेल्यू के रूप में अब वृद्धिशील नहीं है, लेकिन यादृच्छिक, तंत्र को तोड़ रहा है। ऐसा करने का नया तरीका स्विफ्ट 4.2 में अपग्रेड करना और CaseIterable का उपयोग करना है
Yasper

8

कार्यात्मक उद्देश्यों के लिए एक सूची प्राप्त करने के लिए, अभिव्यक्ति का उपयोग करें, EnumName.allCasesजो एक सरणी देता है उदा

EnumName.allCases.map{$0.rawValue} 

आपको दिए गए स्ट्रिंग्स की एक सूची देगा EnumName: String, CaseIterable

नोट: उपयोग allCasesकरने के बजाय AllCases()


8
enum EstimateItemStatus: String, CaseIterable {
  case pending = "Pending"
  case onHold = "OnHold"
  case done = "Done"

  static var statusList: [String] {
    return EstimateItemStatus.allCases.map { $0.rawValue }
  }
}

["लंबित", "ऑनहोल्ड", "पूरा"]


2

स्विफ्ट 5 के लिए अपडेट

सबसे आसान समाधान जो मैंने पाया है .allCasesवह एक ऐसे एनम पर उपयोग करना है जो फैली हुई हैCaseIterable

enum EstimateItemStatus: CaseIterable {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending: return "Pending"
        case .OnHold: return "On Hold"
        case .Done: return "Done"
        }
    }

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

.allCasesकिसी भी CaseIterableEnum पर Collectionउस तत्व की वापसी होगी ।

var myEnumArray = EstimateItemStatus.allCases

CaseIterable के बारे में अधिक जानकारी


विवरण को लागू करने की आवश्यकता नहीं है ()। बस प्रत्येक मामले को स्ट्रिंग के समान करें case OnHold = "On Hold"और जैसे कि प्रत्येक के लिए कच्चे मूल्य बन जाता है।
pnizzle

@pnizzle मुझे पता है, यह वहां है क्योंकि यह मूल प्रश्न में था।
क्रिस्टोफर लार्सन

1

स्विफ्ट 2 के लिए

// Found http://stackoverflow.com/questions/24007461/how-to-enumerate-an-enum-with-string-type
func iterateEnum<T where T: Hashable, T: RawRepresentable>(_: 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
        }
    }
}

func arrayEnum<T where T: Hashable, T: RawRepresentable>(type: T.Type) -> [T]{
    return Array(iterateEnum(type))
}

इसके प्रयेाग के लिए:

arrayEnum(MyEnumClass.self)

क्यों तत्वों 'होता hashValueहो 0..n?
एनआरआईटीएच

1

अनुक्रम से प्रेरणा और कोशिश n त्रुटियों के घंटे के बाद । मुझे आखिरकार Xcode 9.1 पर यह आरामदायक और सुंदर स्विफ्ट 4 रास्ता मिल गया:

protocol EnumSequenceElement: Strideable {
    var rawValue: Int { get }
    init?(rawValue: Int)
}

extension EnumSequenceElement {
    func distance(to other: Self) -> Int {
        return other.rawValue - rawValue
    }

    func advanced(by n: Int) -> Self {
        return Self(rawValue: n + rawValue) ?? self
    }
}

struct EnumSequence<T: EnumSequenceElement>: Sequence, IteratorProtocol {
    typealias Element = T

    var current: Element? = T.init(rawValue: 0)

    mutating func next() -> Element? {
        defer {
            if let current = current {
                self.current = T.init(rawValue: current.rawValue + 1)
            }
        }
        return current
    }
}

उपयोग:

enum EstimateItemStatus: Int, EnumSequenceElement, CustomStringConvertible {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending:
            return "Pending"
        case .OnHold:
            return "On Hold"
        case .Done:
            return "Done"
        }
    }
}

for status in EnumSequence<EstimateItemStatus>() {
    print(status)
}
// Or by countable range iteration
for status: EstimateItemStatus in .Pending ... .Done {
    print(status)
}

आउटपुट:

Pending
On Hold
Done

1

आप उपयोग कर सकते हैं

enum Status: Int{
    case a
    case b
    case c

}

extension RawRepresentable where Self.RawValue == Int {

    static var values: [Self] {
        var values: [Self] = []
        var index = 1
        while let element = self.init(rawValue: index) {
            values.append(element)
            index += 1
        }
        return values
    }
}


Status.values.forEach { (st) in
    print(st)
}

अच्छा! स्विफ्ट 3.2 से 4.1 पर अपग्रेड करने के बाद यह एक समाधान था जिसका मैंने उपयोग किया। हमारे पास मूल रूप से AnyItertor <Self> घोषणाएं थीं। आपका समाधान बहुत साफ और पढ़ने में आसान था। धन्यवाद!
निक एन

2
एक कोड दोष हालांकि यहाँ। यह मामले में पहली वस्तु को याद करता है। बदलें var index = 1 से var index = 0
Nick N

0

यदि आपका एनम वृद्धिशील है और संख्याओं के साथ जुड़ा हुआ है, तो आप उन संख्याओं का उपयोग कर सकते हैं, जो आप मानों के लिए मैप करते हैं, जैसे:

// Swift 3
enum EstimateItemStatus: Int {
    case pending = 1,
    onHold
    done
}

let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }

यह स्ट्रिंग्स या संख्याओं के अलावा किसी अन्य चीज़ से जुड़े एनम के साथ काफी काम नहीं करता है, लेकिन अगर ऐसा है तो यह बहुत अच्छा काम करता है!


0

AllValues ​​बनाने के लिए एक एनुम पर एक्सटेंशन।

extension RawRepresentable where Self: CaseIterable {
      static var allValues: [Self.RawValue] {
        return self.allCases.map { $0.rawValue}
      }
    }

हालांकि यह कोड ओपी की समस्या का समाधान प्रदान कर सकता है, लेकिन यह अत्यधिक अनुशंसा की जाती है कि आप इस संदर्भ में अतिरिक्त संदर्भ क्यों और / या कैसे प्रदान करते हैं। कोड केवल उत्तर आमतौर पर लंबे समय में बेकार हो जाते हैं क्योंकि भविष्य के दर्शकों को इसी तरह की समस्याओं का सामना करना पड़ता है जो समाधान के पीछे के तर्क को समझ नहीं सकते हैं।
ई। ज़ीनतिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.