如何获得Swift枚举的计数?

Rob*_*ins 175 enums count swift

如何确定Swift枚举中的个案数?

(我想避免手动枚举所有值,或者尽可能使用旧的" enum_count技巧 ".)

Mar*_*n R 142

从Swift 4.2(Xcode 10)开始,您可以声明对CaseIterable协议的一致性,这适用于没有相关值的所有枚举:

enum Stuff: CaseIterable {
    case first
    case second
    case third
    case forth
}
Run Code Online (Sandbox Code Playgroud)

现在简单地获得病例数

print(Stuff.allCases.count) // 4
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅


Nat*_*ook 141

我有一篇博文,详细介绍了这一点,但只要您的枚举的原始类型是整数,您就可以这样添加计数:

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
    }()
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然很好,因为您不需要对值进行硬编码,但每次调用时都会实例化每个枚举值.那就是O(n)而不是O(1).:( (14认同)
  • 对于连续的Int来说,这是一个很好的解决方案.我更喜欢略微修改.将静态计数属性转换为静态方法countCases()并将其分配给一个惰性的静态常量caseCount,并通过重复调用提高性能. (4认同)
  • 如果你错过了枚举中的一些价值怎么办?例如`案例A = 1,B = 3`? (3认同)
  • @ShamsAhmed:将计算的var转换为静态var. (2认同)
  • 除了具有"Int"原始值的`enum`之外还有2个假设你忘了提到:带有Int原始值的Swift枚举不必从0开始(即使这是默认行为)并且它们的原始值可以是任意的,它们不必增加1(即使这是默认行为). (2认同)

Ant*_*nio 89

Xcode 10更新

CaseIterable在枚举中采用协议,它提供一个静态allCases属性,其中包含所有枚举案例Collection.只需使用其count属性即可知道枚举有多少个案例.

请参阅马丁的答案以获得一个例子(并提出他的答案,而不是我的答案)


警告:以下方法似乎不再起作用.

我不知道有任何通用方法来计算枚举案例的数量.然而,我注意到hashValue枚举案例的属性是增量的,从零开始,并且顺序由声明案例的顺序决定.因此,最后一个枚举的散列加一个对应于个案的数量.

例如,使用此枚举:

enum Test {
    case ONE
    case TWO
    case THREE
    case FOUR

    static var count: Int { return Test.FOUR.hashValue + 1}
}
Run Code Online (Sandbox Code Playgroud)

count 返回4.

我不能说这是一个规则还是将来会改变,所以使用风险自负 :)

  • 通过未记录的功能生活,死于未记录的功能.我喜欢! (48认同)
  • 如果你不介意明确设置`case ONE = 0`,那么你可以用`rawValue`替换`hashValue`. (15认同)
  • 我们不应该真的依赖于'hashValues`这些东西; 我们所知道的是它是一些随机的唯一值 - 根据一些编译器实现细节,将来很容易改变; 但总的来说,缺乏内置计数功能令人不安. (9认同)
  • 你已经硬编码了哪个常数是最高值的事实,使用像`static var count = 4`这样的东西更好更安全,而不是把你的命运留在未来Swift实现的命运中 (7认同)
  • 这里关注的是使用hashValue的未记录属性,所以我的建议是使用rawValue的文档属性. (3认同)

Tom*_*aia 71

我定义了一个可重用的协议,它根据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
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以重用这个协议,例如如下:

enum Planet : Int, CaseCountable {
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)
Run Code Online (Sandbox Code Playgroud)


dav*_*d72 35

创建静态allValues数组,如本答案所示

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

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

...

let count = ProductCategory.allValues.count
Run Code Online (Sandbox Code Playgroud)

当您想要枚举值时,这也很有用,适用于所有枚举类型

  • 您还可以通过执行`static let count = allValues.count`将计数添加到枚举中.然后,如果需要,你可以将`allValues`设为私有. (2认同)

Zor*_*ayr 15

如果实现没有任何反对使用整数枚举的东西,您可以添加一个额外的成员值来调用Count以表示枚举中的成员数 - 请参阅下面的示例:

enum TableViewSections : Int {
  case Watchlist
  case AddButton
  case Count
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过调用获取枚举中的成员数,TableViewSections.Count.rawValue对于上面的示例,它将返回2.

当您在switch语句中处理枚举时,请确保在遇到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!")
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为Swift更强大的枚举的全部意义在于我们不必使用Objective-C中使用的相同hack:/ (3认同)
  • 同意,有两个限制:必须是整数枚举,必须从零开始并逐步继续. (2认同)

Mat*_*ler 14

这种功能可以返回枚举的计数.

斯威夫特2:

func enumCount<T: Hashable>(_: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
        i += 1
    }
    return i
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特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
   }
Run Code Online (Sandbox Code Playgroud)

  • 这不再适用于Swift 3.试图找出正确的实现,但是空洞 (3认同)

bui*_*ded 9

嘿大家,单元测试怎么样?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

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

    XCTAssert(max == Test.count)
}
Run Code Online (Sandbox Code Playgroud)

这与Antonio的解决方案相结合:

enum Test {

    case one
    case two
    case three
    case four

    static var count: Int { return Test.four.hashValue + 1}
}
Run Code Online (Sandbox Code Playgroud)

在主代码中给你O(1)加上你得到一个失败的测试,如果有人添加枚举案例five并且不更新实现count.


kal*_*ani 9

带索引的字符串枚举

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)!
    }
}
Run Code Online (Sandbox Code Playgroud)

数: eEventTabType.allValues.count

指数: objeEventTabType.index

请享用 :)


rin*_*aro 7

此函数依赖于2个未记录的当前(Swift 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")
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

enum Foo:String {
    case C000 = "foo"
    case C001 = "bar"
    case C002 = "baz"
}
enumCaseCount(Foo) // -> 3
Run Code Online (Sandbox Code Playgroud)


bzz*_*bzz 5

我写了一个简单的扩展,它给出了原始值为整数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())
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,它给了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())
    }
}
Run Code Online (Sandbox Code Playgroud)

它与Tom Pelaia发布的方法非常相似,但适用于所有整数类型.


小智 5

enum EnumNameType: Int {
    case first
    case second
    case third

    static var count: Int { return EnumNameType.third.rawValue + 1 }
}

print(EnumNameType.count) //3
Run Code Online (Sandbox Code Playgroud)

或者

enum EnumNameType: Int {
    case first
    case second
    case third
    case count
}

print(EnumNameType.count.rawValue) //3
Run Code Online (Sandbox Code Playgroud)

*在 Swift 4.2 (Xcode 10) 上可以使用:

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

print(EnumNameType.allCases.count) //3
Run Code Online (Sandbox Code Playgroud)