programing

Swift 열거형 카운트를 얻으려면 어떻게 해야 합니까?

linuxpc 2023. 4. 16. 14:43
반응형

Swift 열거형 카운트를 얻으려면 어떻게 해야 합니까?

Swift 열거형에서 케이스 수를 확인하려면 어떻게 해야 합니까?

(모든 값을 수동으로 열거하거나 가능하면 이전 "enum_count trick"을 사용하지 않도록 합니다.)

4.2 10에서는 Swift 4.2(XΩ 10)에 하고 있다고 할 수 .CaseIterable이 없는 에 대해 합니다.

enum Stuff: CaseIterable {
    case first
    case second
    case third
    case forth
}

환자 수는 이제 간단히 다음 방법으로 얻을 수 있습니다.

print(Stuff.allCases.count) // 4

상세한 것에 대하여는, 을 참조해 주세요.

자세한 내용은 블로그 투고입니다만, enum의 raw 타입이 정수인 경우는, 다음과 같이 카운트를 추가할 수 있습니다.

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

Xcode 10 업데이트

채용하다CaseIterable 「Natic」, 「Natic」의 「Natic」를 합니다.allCases 케이스를 .Collection 하세요.count속성을 사용하여 열거에 포함된 케이스 수를 알 수 있습니다.

예를 들어 마틴의 답변을 참조한다(내 답변이 아닌 마틴의 답변을 상향 투표한다).


경고: 아래 방법이 더 이상 작동하지 않는 것 같습니다.

나는 열거 사례의 수를 세는 일반적인 방법을 알지 못한다.이 문구가 요.hashValue열거 케이스의 속성은 0부터 시작하여 케이스가 선언된 순서에 따라 결정되는 순서로 증분됩니다.따라서 마지막 열거형 + 1의 해시는 사례 수에 해당합니다.

예를 들어 다음과 같습니다.

enum Test {
    case ONE
    case TWO
    case THREE
    case FOUR

    static var count: Int { return Test.FOUR.hashValue + 1}
}

count는 44를 합니다.

그것이 규칙인지, 앞으로 바뀔지는 말할 수 없기 때문에, 자신의 책임으로 사용해 주세요.

저는 Nate Cook이 게시한 접근법에 따라 자동으로 케이스 카운트를 수행하는 재사용 가능한 프로토콜을 정의합니다.

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)

답변에 표시된 것처럼 정적 allValues 배열 생성

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

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

...

let count = ProductCategory.allValues.count

이것은 값을 열거하는 경우에도 유용하며 모든 Enum 유형에 대해 작동합니다.

에 정수 하는 것에 않는 는, 「정수 에넘」이라고 하는 할 수 .Count멤버의 다음 、 to 、 to 、 to 、 to 、 to to to to to to to 。이치노

enum TableViewSections : Int {
  case Watchlist
  case AddButton
  case Count
}

의 수를 알 수.TableViewSections.Count.rawValue2번으로 하다

" " "가 했을 때 .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 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

index : ":objeEventTabType.index

즐기세요 :)

오, 여러분, 유닛 테스트는요?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

    var max: Int = 0
    while let _ = Test(rawValue: max) { max += 1 }

    XCTAssert(max == Test.count)
}

이것은 Antonio의 솔루션과 조합되어 있습니다.

enum Test {

    case one
    case two
    case three
    case four

    static var count: Int { return Test.four.hashValue + 1}
}

메인 코드에서는 O(1)와 함께 누군가가 열거 케이스를 추가하면 불합격 테스트를 받습니다.five,, 의, 의, 의, 의, 의, 니, 니, 니, 니, 니, 니, 니, 니, 니, 니, 니, 니,count.

이 기능은 2개의 문서화되지 않은 전류(Swift 1.1)에 의존합니다.enum★★★★

  • of리 の of of の of of of의 enum의 지표일 뿐이다.case가 2 ~256 인 「2 ~ 256 」입니다UInt8.
  • 경우,enum유효하지 않은 케이스인덱스에서 비트캐스트되었습니다.hashValue0

따라서 고객님의 책임 하에 사용하십시오. :)

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

에 raw raw a enum을 부여하는 간단한 확장자를 .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())
    }
}

도 행행 the the the the the the the the the 。count을 property property로 설정합니다.OptionSetType에서는, 또 입니다.CaseCountable protocol: : protocol Enum:

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

Tom Pelaia가 게시한 접근법과 매우 유사하지만 모든 정수형에 대해 작동합니다.

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

*Swift 4.2(X코드 10)에서는 다음을 사용할 수 있습니다.

enum EnumNameType: CaseIterable {
    case first
    case second
    case third
}

print(EnumNameType.allCases.count) //3

물론 동적인 것은 아니지만 Enum에 추가된 정적 변수를 통해 많은 용도로 사용할 수 있습니다.

static var count: Int{ return 7 }

다음 ''로 합니다.EnumName.count

사용 예에서는 여러 사용자가 열거형에 키를 추가할 수 있는 코드 기반에서 이러한 모든 경우를 allKeys 속성에서 사용할 수 있어야 하므로 allKeys를 열거형 키에 대해 검증하는 것이 중요합니다.이는 누군가가 키를 모든 키 목록에 추가하는 것을 잊어버리는 것을 방지하기 위한 것입니다.allKeys 배열의 수(듀페를 피하기 위해 세트로 처음 작성됨)를 열거형 키 수와 일치시키면 키가 모두 존재합니다.

위의 답변 중 일부는 Swift 2에서 이를 달성하는 방법을 보여주지만 Swift 3에서는 작동하지 않습니다.다음은 Swift 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)
}

사용 사례에 따라 각 요청에 대해 allKey를 사용하는 데 따른 오버헤드를 피하기 위해 개발 중에 테스트를 실행하는 것이 좋습니다.

왜 그렇게 복잡하게 만드세요?Int enum의 가장 심플한 카운터는 다음과 같습니다.

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

마지막 열거를 기준으로 코드를 작성하지 않으려면 열거형 내부에 이 함수를 만들 수 있습니다.

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
}

Swift 3 버전은Intenum을 합니다.

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

크레딧: bzz와 Nate Cook의 답변을 바탕으로 합니다.

" " " 」IntegerType에서는 (Swift 3 서서에에에에에에에에에에에에에에에에에에에에 ( ( ( ()로 이름이 되었습니다).Integer이 많이 이기 때문에 되지 않습니다는 기능이 많이 없는 고도로 단편화된 범용 타입이기 때문에 지원되지 않습니다. successor【Swift 3】【Swift 3】★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.

Code Commander에서 Nate Cooks에 대한 답변은 여전히 유효합니다.

값을 하드코드할 필요가 없기 때문에 좋지만 호출될 때마다 모든 열거값이 인스턴스화됩니다.그것은 O(1)가 아닌 O(n)입니다.

내가 아는 한, 이것을 프로토콜 확장자로 사용할 때(그리고 Nate Cook처럼 각 열거형에는 구현되지 않음) 현재 해결 방법이 없습니다.이는 범용 유형에서는 정적 저장 속성이 지원되지 않기 때문입니다.

어쨌든, 작은 에넘들에게는 이것은 문제가 되지 않을 것이다.는 case음음음 a a a a a a a음음 。section.count★★★★★★에UITableViews이치노

마티외 리글러의 답변을 확장하면, 이것은 제네릭스를 사용하지 않아도 되는 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)를 생성하여 해결했습니다(Swift 1.2 사용)."all" 변수에는 열거형 내의 모든 요소의 배열이 포함되므로 카운트에 all.count를 사용할 수 있습니다.

Int 유형의 원시 값을 사용하는 Enum에서만 작동하지만 다른 유형에 대한 영감을 제공할 수 있습니다.

또한 위와 다른 곳에서 읽은 "번호부여의 격차"와 "반복하는 데 너무 많은 시간" 문제도 해결합니다.

EnumIntArray 프로토콜을 Enum에 추가한 후 enum을 호출하여 "all" 정적 변수를 정의하는 것입니다.IntArray가 기능하여 첫 번째 요소(번호에 공백이 있는 경우 마지막 요소)와 함께 제공합니다.

정적 변수는 한 번만 초기화되므로 모든 원시 값을 통과하는 오버헤드는 프로그램에 한 번만 적용됩니다.

예(갭 없음):

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 외부에합니다.enum 부 、 outside 、 outside 、 outside 、 outside 、 outside outside outside outside outside outside 。

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에서 나왔으며 다른 사람들이 제안한 답변과 유사합니다.이것은 Swift 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 SomeEnum {
  case one
  case two(String)
  case three(String, Int)
}
  • CaseIterable 제공하지 않습니다allCases자동으로.
  • 요.Int사건들을 계산하기 위해서요

우리가 할 수 있는 것은, 동력을 사용하는 것입니다.switch ★★★★★★★★★★★★★★★★★」fallthrough키워드를 지정합니다.

extension SomeEnum {
  static var casesCount: Int {
    var sum = 0

    switch Self.one { // Potential problem
       case one:
         sum += 1
         fallthrough

       case two:
         sum += 1
         fallthrough

       case three:
         sum += 1
    }

    return sum
  }
}

, 이제 이렇게 수 요.SomeEnum.casesCount.

비고:

  • .switch Self.one {...솔루션은 할 수 .이 솔루션은 쉽게 해킹할 수 있습니다.하지만 유닛 테스트에만 사용했기 때문에 문제 없습니다.
  • 연관된 값과 함께 사례 수를 enum으로 가져와야 하는 경우 코드 생성을 고려하십시오.
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

단, non-enum 타입에서의 사용에 주의해 주십시오.회피책은 다음과 같습니다.

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

열거의 마지막 값에 1을 더한 정적 상수를 사용할 수 있습니다.

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

이것은 사소한 것이지만, 보다 나은 O(1) 솔루션은 다음과 같습니다(enum이 다음과 같은 경우에만 해당).Intx)

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을 사용하다

언급URL : https://stackoverflow.com/questions/27094878/how-do-i-get-the-count-of-a-swift-enum

반응형