मैं स्विफ्ट एनम में मामलों की संख्या कैसे निर्धारित कर सकता हूं?
(मैं सभी मूल्यों के माध्यम से मैन्युअल रूप से गणना करने से बचना चाहूंगा , या यदि संभव हो तो पुरानी " enum_count चाल " का उपयोग कर सकता हूं ।)
मैं स्विफ्ट एनम में मामलों की संख्या कैसे निर्धारित कर सकता हूं?
(मैं सभी मूल्यों के माध्यम से मैन्युअल रूप से गणना करने से बचना चाहूंगा , या यदि संभव हो तो पुरानी " enum_count चाल " का उपयोग कर सकता हूं ।)
जवाबों:
स्विफ्ट 4.2 (एक्सकोड 10) के रूप में आप CaseIterable
प्रोटोकॉल के अनुरूप घोषित कर सकते हैं , यह संबद्ध मूल्यों के बिना सभी गणना के लिए काम करता है:
enum Stuff: CaseIterable {
case first
case second
case third
case forth
}
मामलों की संख्या अब बस के साथ प्राप्त की है
print(Stuff.allCases.count) // 4
अधिक जानकारी के लिए देखें
मेरे पास एक ब्लॉग पोस्ट है जो इस पर अधिक विस्तार से जाती है, लेकिन जब तक आपके एनम का कच्चा प्रकार एक पूर्णांक है, तब तक आप इस तरह से एक गणना जोड़ सकते हैं:
enum Reindeer: Int {
case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
case Rudolph
static let count: Int = {
var max: Int = 0
while let _ = Reindeer(rawValue: max) { max += 1 }
return max
}()
}
case A=1, B=3
?
enum
एक होने Int
स्विफ्ट enum के इंट कच्चे मूल्यों के साथ 0 (भले ही है कि डिफ़ॉल्ट व्यवहार) और उनके कच्चे मूल्यों से शुरू करने के लिए मनमाने ढंग से किया जा सकता है की जरूरत नहीं है, वे की जरूरत नहीं है: कच्चे मूल्य है कि आप उल्लेख करना भूल गया 1 से वेतन वृद्धि (भले ही वह डिफ़ॉल्ट व्यवहार हो)।
Xcode 10 अपडेट
अपनाने CaseIterable
enum में प्रोटोकॉल, तो वह एक स्थिर प्रदान करता है allCases
संपत्ति है जो एक के रूप में सभी enum मामलों में शामिल है Collection
। बस इसका उपयोग करेंcount
एनुम के कितने मामले हैं, यह जानने के लिए संपत्ति ।
उदाहरण के लिए मार्टिन का उत्तर देखें (और मेरे बजाय उसके जवाबों को आगे बढ़ाएं)
चेतावनी : नीचे दी गई विधि अब काम नहीं करती है।
मैं किसी भी सामान्य विधि के बारे में पता नहीं कर रहा हूँ कि एनम मामलों की संख्या की गणना करें। हालांकि मैंने देखा है कि hashValue
एनम मामलों की संपत्ति में वृद्धि होती है, जो शून्य से शुरू होती है, और उस क्रम से निर्धारित होती है जिसमें मामलों को घोषित किया जाता है। तो, अंतिम ईनम प्लस का हैश मामलों की संख्या से मेल खाता है।
इस एनम के साथ उदाहरण के लिए:
enum Test {
case ONE
case TWO
case THREE
case FOUR
static var count: Int { return Test.FOUR.hashValue + 1}
}
count
रिटर्न 4।
मैं यह नहीं कह सकता कि यदि यह नियम है या भविष्य में यह कभी बदलेगा, तो अपने जोखिम पर उपयोग करें :)
hashValues
इन चीजों पर निर्भर नहीं होना चाहिए ; हम सभी जानते हैं कि यह कुछ यादृच्छिक अद्वितीय मूल्य है - कुछ संकलक कार्यान्वयन विवरण के आधार पर भविष्य में बहुत आसानी से बदल सकते हैं; लेकिन कुल मिलाकर, अंतर्निहित गिनती कार्यक्षमता की कमी परेशान करती है।
case ONE = 0
, तो आप बदल सकते हैं hashValue
के साथ rawValue
।
static var count = 4
स्विफ्ट के भविष्य के कार्यान्वयन के भाग्य में अपने भाग्य को छोड़ने के बजाय सिर्फ कुछ का उपयोग करने के लिए बेहतर और सुरक्षित है
मैं एक पुन: प्रयोज्य प्रोटोकॉल को परिभाषित करता हूं जो नैट कुक द्वारा पोस्ट किए गए दृष्टिकोण के आधार पर स्वचालित रूप से केस काउंट करता है।
protocol CaseCountable {
static var caseCount: Int { get }
}
extension CaseCountable where Self: RawRepresentable, Self.RawValue == Int {
internal static var caseCount: Int {
var count = 0
while let _ = Self(rawValue: count) {
count += 1
}
return count
}
}
फिर मैं उदाहरण के लिए इस प्रोटोकॉल का पुन: उपयोग कर सकता हूं:
enum Planet : Int, CaseCountable {
case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)
count++
के लिए count+=1
के बाद से ++
अंकन स्विफ्ट 3 में निकाल दिया जाएगा
static var caseCount: Int { get }
? क्यों की जरूरत है static func
?
case A=1, B=3
?
0
और कोई अंतराल नहीं है।
जैसा कि इस उत्तर में दिखाया गया है, स्थिर allValues सरणी बनाएँ
enum ProductCategory : String {
case Washers = "washers", Dryers = "dryers", Toasters = "toasters"
static let allValues = [Washers, Dryers, Toasters]
}
...
let count = ProductCategory.allValues.count
यह तब भी मददगार होता है जब आप मूल्यों की गणना करना चाहते हैं, और सभी Enum प्रकारों के लिए काम करते हैं
static let count = allValues.count
। फिर आप allValues
चाहें तो निजी बना सकते हैं ।
यदि पूर्णांक एनमों का उपयोग करने के खिलाफ कार्यान्वयन में कुछ भी नहीं है, तो आप एनम Count
में सदस्यों की संख्या का प्रतिनिधित्व करने के लिए बुलाया एक अतिरिक्त सदस्य मूल्य जोड़ सकते हैं - नीचे उदाहरण देखें:
enum TableViewSections : Int {
case Watchlist
case AddButton
case Count
}
अब आप कॉल करके enum में सदस्यों की संख्या प्राप्त कर सकते हैं, TableViewSections.Count.rawValue
जो ऊपर दिए गए उदाहरण के लिए 2 लौटाएगा।
जब आप एक स्विच स्टेटमेंट में एनम को संभाल रहे हैं, तो उस Count
सदस्य का सामना करते समय एक जोरदार विफलता फेंकना सुनिश्चित करें जहां आप इसकी उम्मीद नहीं करते हैं:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
switch(currentSection) {
case .Watchlist:
return watchlist.count
case .AddButton:
return 1
case .Count:
assert(false, "Invalid table view section!")
}
}
इस तरह का फंक्शन आपके एनम की गिनती लौटाने में सक्षम है।
स्विफ्ट 2 :
func enumCount<T: Hashable>(_: T.Type) -> Int {
var i = 1
while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
i += 1
}
return i
}
स्विफ्ट 3 :
func enumCount<T: Hashable>(_: T.Type) -> Int {
var i = 1
while (withUnsafePointer(to: &i, {
return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
}).hashValue != 0) {
i += 1
}
return i
}
enum
है भी Hashable
एक ही प्रकार के।
इंडेक्स के साथ स्ट्रिंग एनम
enum eEventTabType : String {
case Search = "SEARCH"
case Inbox = "INBOX"
case Accepted = "ACCEPTED"
case Saved = "SAVED"
case Declined = "DECLINED"
case Organized = "ORGANIZED"
static let allValues = [Search, Inbox, Accepted, Saved, Declined, Organized]
var index : Int {
return eEventTabType.allValues.indexOf(self)!
}
}
गणना: eEventTabType.allValues.count
सूचकांक: objeEventTabType.index
का आनंद लें :)
ओह हे सब लोग, यूनिट परीक्षणों के बारे में क्या?
func testEnumCountIsEqualToNumberOfItemsInEnum() {
var max: Int = 0
while let _ = Test(rawValue: max) { max += 1 }
XCTAssert(max == Test.count)
}
यह एंटोनियो के समाधान के साथ संयुक्त है:
enum Test {
case one
case two
case three
case four
static var count: Int { return Test.four.hashValue + 1}
}
मुख्य कोड में आपको O (1) प्लस मिलता है, यदि आपको कोई फेल होने वाला टेस्ट मिलता है, तो कोई एनुम केस जोड़ता है five
और कार्यान्वयन को अपडेट नहीं करता है count
।
यह फ़ंक्शन 2 अनिर्धारित वर्तमान (स्विफ्ट 1.1) enum
व्यवहार पर निर्भर करता है:
enum
सिर्फ एक सूचकांक है case
। यदि केस संख्या 2 से 256 तक है, तो यह है UInt8
।enum
से बिट-कास्ट किया गया है , तो यह हैhashValue
0
तो अपने जोखिम पर उपयोग करें :)
func enumCaseCount<T:Hashable>(t:T.Type) -> Int {
switch sizeof(t) {
case 0:
return 1
case 1:
for i in 2..<256 {
if unsafeBitCast(UInt8(i), t).hashValue == 0 {
return i
}
}
return 256
case 2:
for i in 257..<65536 {
if unsafeBitCast(UInt16(i), t).hashValue == 0 {
return i
}
}
return 65536
default:
fatalError("too many")
}
}
उपयोग:
enum Foo:String {
case C000 = "foo"
case C001 = "bar"
case C002 = "baz"
}
enumCaseCount(Foo) // -> 3
मैंने एक साधारण एक्सटेंशन लिखा है जो सभी एनमों को देता है जहां कच्चा मूल्य एक count
संपत्ति है:
extension RawRepresentable where RawValue: IntegerType {
static var count: Int {
var i: RawValue = 0
while let _ = Self(rawValue: i) {
i = i.successor()
}
return Int(i.toIntMax())
}
}
दुर्भाग्य से यह उस count
संपत्ति को देता है OptionSetType
जहां यह ठीक से काम नहीं करेगा, इसलिए यहां एक और संस्करण है जिसे CaseCountable
किसी भी एनम के लिए प्रोटोकॉल के लिए स्पष्ट अनुरूपता की आवश्यकता होती है जिसे आप गिनना चाहते हैं:
protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
static var count: Int {
var i: RawValue = 0
while let _ = Self(rawValue: i) {
i = i.successor()
}
return Int(i.toIntMax())
}
}
यह टॉम पेलिया द्वारा पोस्ट किए गए दृष्टिकोण के समान है, लेकिन सभी पूर्णांक प्रकारों के साथ काम करता है।
बेशक, यह गतिशील नहीं है, लेकिन कई उपयोगों के लिए आप अपने Enum में जोड़े गए स्थिर संस्करण के साथ प्राप्त कर सकते हैं
static var count: Int{ return 7 }
और फिर इसका उपयोग करें EnumName.count
enum EnumNameType: Int {
case first
case second
case third
static var count: Int { return EnumNameType.third.rawValue + 1 }
}
print(EnumNameType.count) //3
या
enum EnumNameType: Int {
case first
case second
case third
case count
}
print(EnumNameType.count.rawValue) //3
* स्विफ्ट 4.2 पर (Xcode 10) उपयोग कर सकते हैं:
enum EnumNameType: CaseIterable {
case first
case second
case third
}
print(EnumNameType.allCases.count) //3
मेरे उपयोग के मामले के लिए, एक कोडबेस में जहां कई लोग एक enum में चाबियाँ जोड़ सकते हैं, और ये सभी मामले allKeys संपत्ति में उपलब्ध होने चाहिए, यह महत्वपूर्ण है कि सभीKeyum में कुंजियों के विरुद्ध मान्य किया जाए। यह किसी को सभी कुंजी सूची में अपनी कुंजी जोड़ने के लिए भूल जाने से बचने के लिए है।एलुम में कुंजियों की संख्या के खिलाफ allKeys सरणी की गिनती (पहली बार डुप्स से बचने के लिए एक सेट के रूप में बनाई गई) से मेल खाते हुए सुनिश्चित करता है कि वे सभी मौजूद हैं।
ऊपर दिए गए कुछ उत्तर स्विफ्ट 2 में इसे प्राप्त करने का तरीका दिखाते हैं लेकिन स्विफ्ट 3 में कोई भी काम नहीं करता है । यहाँ स्विफ्ट 3 स्वरूपित संस्करण है:
static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
var i = 1
while (withUnsafePointer(to: &i) {
$0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
}) {
i += 1
}
return i
}
static var allKeys: [YourEnumTypeHere] {
var enumSize = enumCount(YourEnumTypeHere.self)
let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
guard keys.count == enumSize else {
fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
}
return Array(keys)
}
आपके उपयोग के मामले के आधार पर, आप प्रत्येक अनुरोध पर allKeys का उपयोग करने के ओवरहेड से बचने के लिए विकास में परीक्षण चलाना चाहते हैं।
आप इसे इतना जटिल क्यों बनाते हैं? Int enum के SIMPLEST काउंटर को जोड़ना है:
case Count
अंततः। और ... वायोला - अब आपके पास गिनती है - तेज और सरल
0
और अनुक्रम में कोई अंतराल नहीं होता है।
यदि आप अंतिम एनम में अपने कोड को आधार नहीं बनाना चाहते हैं तो आप अपने एनम के अंदर यह फ़ंक्शन बना सकते हैं।
func getNumberOfItems() -> Int {
var i:Int = 0
var exit:Bool = false
while !exit {
if let menuIndex = MenuIndex(rawValue: i) {
i++
}else{
exit = true
}
}
return i
}
एक स्विफ्ट 3 संस्करण Int
प्रकार के साथ काम कर रहा है :
protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue == Int {
static var count: RawValue {
var i: RawValue = 0
while let _ = Self(rawValue: i) { i += 1 }
return i
}
}
क्रेडिट: बज़ और नैट कुक के उत्तरों के आधार पर।
जेनेरिक IntegerType
(स्विफ्ट 3 का नाम बदला हुआ Integer
) समर्थित नहीं है, क्योंकि यह एक भारी खंडित सामान्य प्रकार है जिसमें बहुत सारे कार्यों का अभाव है। successor
अब स्विफ्ट 3 के साथ उपलब्ध नहीं है।
ज्ञात हो कि कोड कमांडर से लेकर नैट कुक के उत्तर तक की टिप्पणी अभी भी मान्य है:
हालांकि अच्छा है क्योंकि आपको किसी मूल्य को हार्डकोड करने की आवश्यकता नहीं है, यह हर बार जब यह कहा जाता है, तो हर एनम मूल्य को तुरंत कर देगा। O (1) के बजाय O (n) है।
जहां तक मुझे पता है कि वर्तमान में प्रोटोकॉल एक्सटेंशन के रूप में उपयोग करने पर कोई वर्कअराउंड नहीं है (और नैट कुक की तरह प्रत्येक एनम में लागू नहीं किया गया) स्थैतिक संग्रहीत गुणों के कारण जेनेरिक प्रकारों में समर्थित नहीं है।
वैसे भी, छोटी दुश्मनी के लिए यह कोई मुद्दा नहीं होना चाहिए। एक सामान्य उपयोग का मामला पहले से ही ज़ॉएर द्वारा उल्लिखित के section.count
लिए होगा UITableViews
।
Matthieu Riegler उत्तर का विस्तार करते हुए, यह Swift 3 के लिए एक समाधान है जिसमें जेनेरिक के उपयोग की आवश्यकता नहीं है, और इसे आसानी से enum प्रकार का उपयोग करके बुलाया जा सकता है EnumType.elementsCount
:
extension RawRepresentable where Self: Hashable {
// Returns the number of elements in a RawRepresentable data structure
static var elementsCount: Int {
var i = 1
while (withUnsafePointer(to: &i, {
return $0.withMemoryRebound(to: self, capacity: 1, { return
$0.pointee })
}).hashValue != 0) {
i += 1
}
return i
}
मैंने एक प्रोटोकॉल (EnumIntArray) और एक वैश्विक उपयोगिता फ़ंक्शन (enumIntArray) बनाकर अपने लिए इस समस्या को हल किया, जो किसी भी एनम (स्विफ्ट 1.2 का उपयोग करके "ऑल" वैरिएबल को जोड़ना बहुत आसान बनाता है। "सभी" चर में सभी तत्वों की एक सरणी समाहित होगी ताकि आप गणना के लिए all.count का उपयोग कर सकें
यह केवल उन एनमों के साथ काम करता है जो Int के कच्चे मूल्यों का उपयोग करते हैं लेकिन शायद यह अन्य प्रकारों के लिए कुछ प्रेरणा प्रदान कर सकता है।
यह "गैप इन नंबरिंग" और "अत्यधिक समय को पुनरावृति करने" के लिए संबोधित करता है।
अपने Enum में EnumIntArray प्रोटोकॉल को जोड़ने और उसके बाद enumIntArray फ़ंक्शन को कॉल करके "सब" स्टैटिक वैरिएबल को परिभाषित करने और इसे पहले तत्व (और अगर नंबरिंग में अंतराल हैं तो आखिरी) प्रदान करने पर विचार करना है।
क्योंकि स्टेटिक वैरिएबल केवल एक बार इनिशियलाइज़ होता है, सभी कच्चे मूल्यों से गुजरने का ओवरहेड केवल एक बार आपके प्रोग्राम को हिट करता है।
उदाहरण (अंतराल के बिना):
enum Animals:Int, EnumIntArray
{
case Cat=1, Dog, Rabbit, Chicken, Cow
static var all = enumIntArray(Animals.Cat)
}
उदाहरण (अंतराल के साथ):
enum Animals:Int, EnumIntArray
{
case Cat = 1, Dog,
case Rabbit = 10, Chicken, Cow
static var all = enumIntArray(Animals.Cat, Animals.Cow)
}
यहाँ वह कोड है जो इसे लागू करता है:
protocol EnumIntArray
{
init?(rawValue:Int)
var rawValue:Int { get }
}
func enumIntArray<T:EnumIntArray>(firstValue:T, _ lastValue:T? = nil) -> [T]
{
var result:[T] = []
var rawValue = firstValue.rawValue
while true
{
if let enumValue = T(rawValue:rawValue++)
{ result.append(enumValue) }
else if lastValue == nil
{ break }
if lastValue != nil
&& rawValue > lastValue!.rawValue
{ break }
}
return result
}
या आप बस एनम के _count
बाहर परिभाषित कर सकते हैं , और इसे सांख्यिकीय रूप से संलग्न कर सकते हैं:
let _count: Int = {
var max: Int = 0
while let _ = EnumName(rawValue: max) { max += 1 }
return max
}()
enum EnumName: Int {
case val0 = 0
case val1
static let count = _count
}
इस तरह से आप चाहे जितनी भी पहेली बना लें, यह केवल एक बार ही बनेगी।
(यदि static
ऐसा हो तो इस उत्तर को हटा दें )
निम्नलिखित विधि CoreKit से आती है और कुछ अन्य लोगों द्वारा सुझाए गए उत्तरों के समान है। यह स्विफ्ट 4 के साथ काम करता है।
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
static var allValues: [Self] { get }
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
public static var allValues: [Self] {
return Array(self.cases())
}
}
enum Weekdays: String, EnumCollection {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
फिर आपको बस कॉल करने की जरूरत है Weekdays.allValues.count
।
enum WeekDays : String , CaseIterable
{
case monday = "Mon"
case tuesday = "Tue"
case wednesday = "Wed"
case thursday = "Thu"
case friday = "Fri"
case saturday = "Sat"
case sunday = "Sun"
}
var weekdays = WeekDays.AllCases()
print("\(weekdays.count)")
struct HashableSequence<T: Hashable>: SequenceType {
func generate() -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
if next.hashValue == i {
i += 1
return next
}
return nil
}
}
}
extension Hashable {
static func enumCases() -> Array<Self> {
return Array(HashableSequence())
}
static var enumCount: Int {
return enumCases().enumCount
}
}
enum E {
case A
case B
case C
}
E.enumCases() // [A, B, C]
E.enumCount // 3
लेकिन गैर-एनम प्रकारों पर उपयोग के साथ सावधान रहें। कुछ समाधान हो सकता है:
struct HashableSequence<T: Hashable>: SequenceType {
func generate() -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
guard sizeof(T) == 1 else {
return nil
}
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
if next.hashValue == i {
i += 1
return next
}
return nil
}
}
}
extension Hashable {
static func enumCases() -> Array<Self> {
return Array(HashableSequence())
}
static var enumCount: Int {
return enumCases().count
}
}
enum E {
case A
case B
case C
}
Bool.enumCases() // [false, true]
Bool.enumCount // 2
String.enumCases() // []
String.enumCount // 0
Int.enumCases() // []
Int.enumCount // 0
E.enumCases() // [A, B, C]
E.enumCount // 4
यह एक स्थिर स्थिरांक का उपयोग कर सकता है जिसमें एन्यूमरेशन प्लस का अंतिम मान होता है।
enum Color : Int {
case Red, Orange, Yellow, Green, Cyan, Blue, Purple
static let count: Int = Color.Purple.rawValue + 1
func toUIColor() -> UIColor{
switch self {
case .Red:
return UIColor.redColor()
case .Orange:
return UIColor.orangeColor()
case .Yellow:
return UIColor.yellowColor()
case .Green:
return UIColor.greenColor()
case .Cyan:
return UIColor.cyanColor()
case .Blue:
return UIColor.blueColor()
case .Purple:
return UIColor.redColor()
}
}
}
यह मामूली है, लेकिन मुझे लगता है कि एक बेहतर ओ (1) समाधान निम्नलिखित होगा ( केवल अगर आपकी एनम Int
एक्स पर शुरू हो रही है, आदि):
enum Test : Int {
case ONE = 1
case TWO
case THREE
case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value
case COUNT
static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential
}
वर्तमान चयनित उत्तर मुझे अभी भी लगता है कि सभी विवरणों के लिए सबसे अच्छा उत्तर है, जब तक कि आप Int
तब काम कर रहे हों, मैं इस समाधान की सलाह देता हूं।
guard
विरुद्ध है COUNT
और एक त्रुटि, गलत रिटर्न आदि को फेंकता है।