Luc*_*ien 510 string enums enumerate swift
enum Suit: String {
case spades = "?"
case hearts = "?"
case diamonds = "?"
case clubs = "?"
}
Run Code Online (Sandbox Code Playgroud)
例如,我该怎么做:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
Run Code Online (Sandbox Code Playgroud)
结果示例:
?
?
?
?
Run Code Online (Sandbox Code Playgroud)
rou*_*ter 514
这篇文章与此相关https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-swift
基本上提出的解决方案是
enum ProductCategory : String {
case Washers = "washers", Dryers = "dryers", Toasters = "toasters"
static let allValues = [Washers, Dryers, Toasters]
}
for category in ProductCategory.allValues{
//Do something
}
Run Code Online (Sandbox Code Playgroud)
rin*_*aro 275
我创建了一个实用函数iterateEnum()来迭代任意enum类型的case .
以下是示例用法:
enum Suit: String {
case Spades = "?"
case Hearts = "?"
case Diamonds = "?"
case Clubs = "?"
}
for f in iterateEnum(Suit) {
println(f.rawValue)
}
Run Code Online (Sandbox Code Playgroud)
输出:
?
?
?
?
Run Code Online (Sandbox Code Playgroud)
但是,这仅用于调试或测试目的:这依赖于几个未记录的当前(Swift1.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
}
}
Run Code Online (Sandbox Code Playgroud)
根本的想法是:
enum- 不包括enum具有关联类型的s - 只是案例的索引,当案例的计数是2...256,它与UInt8,何时257...65536,UInt16等等时相同.因此,它可以unsafeBitcast来自相应的无符号整数类型..hashValue 枚举值的大小与大小写的索引相同..hashValue从无效索引中获取的枚举值是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
}
}
Run Code Online (Sandbox Code Playgroud)
增加: 修改为Swift3
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
}
}
Run Code Online (Sandbox Code Playgroud)
增加: 针对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
}
}
Run Code Online (Sandbox Code Playgroud)
Cœu*_*œur 230
从Swift 4.2开始(使用Xcode 10),只需添加协议一致性即可CaseIterable从allCases以下方面受益:
extension Suit: CaseIterable {}
Run Code Online (Sandbox Code Playgroud)
然后,这将打印所有可能的值:
Suit.allCases.forEach {
print($0.rawValue)
}
Run Code Online (Sandbox Code Playgroud)
只是模仿Swift 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
Run Code Online (Sandbox Code Playgroud)
sdd*_*sma 129
其他解决方案有效但它们都假设例如可能的等级和套装的数量,或者第一和最后等级可能是什么.诚然,在可预见的未来,一副牌的布局可能不会有太大变化.但是,一般来说,编写尽可能少的假设的代码更为简洁.我的解决方案
我已经在套装枚举中添加了原始类型,因此我可以使用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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
下面是Card的createDeck()方法的实现.init(rawValue :)是一个可用的初始化程序并返回一个可选项.通过在while语句中解包和检查它的值,不需要假设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
}
}
Run Code Online (Sandbox Code Playgroud)
以下是调用createDeck方法的方法:
let card = Card(rank: Rank.Ace, suit: Suit.Clubs)
let deck = card.createDeck()
Run Code Online (Sandbox Code Playgroud)
Kam*_*xom 75
所以我在位和字节中偶然发现并创建了一个扩展(我后来发现它与@rintaro的答案非常相似).它可以像这样使用:
enum E : EnumCollection {
case A, B, C
}
Array(E.cases()) // [A, B, C]
Run Code Online (Sandbox Code Playgroud)
值得注意的是它可以在任何枚举上使用(没有相关值).请注意,这不适用于没有案例的枚举.
与@rintaro的回答一样,此代码使用枚举的基础表示.这种表示没有记录,将来可能会改变,这会破坏它 - >我不建议在生产中使用它.
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(我不知道为什么我需要它typealias,但编译器抱怨没有它)
(我对这个答案进行了大的修改,看过去版本的编辑)
Rnd*_*Tsk 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)!
}
Run Code Online (Sandbox Code Playgroud)
在开放或闭合范围(..<或...)上迭代将在内部调用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
}
Run Code Online (Sandbox Code Playgroud)
Dil*_*ari 19
更新代码:Swift 4.2/Swift 5
\nenum Suit: String, CaseIterable {\n case spades = "\xe2\x99\xa0"\n case hearts = "\xe2\x99\xa5"\n case diamonds = "\xe2\x99\xa6"\n case clubs = "\xe2\x99\xa3"\n}\nRun Code Online (Sandbox Code Playgroud)\n要根据问题访问输出:
\nfor suitKey in Suit.allCases {\n print(suitKey.rawValue)\n}\nRun Code Online (Sandbox Code Playgroud)\n输出 :
\n\xe2\x99\xa0\n\xe2\x99\xa5\n\xe2\x99\xa6\n\xe2\x99\xa3\nRun Code Online (Sandbox Code Playgroud)\nCaseIterable:提供其所有值的集合。\n符合 CaseIterable 协议的类型通常是没有关联值的枚举。使用 CaseIterable 类型时,可以使用 type\xe2\x80\x99s allCases 属性访问所有 type\xe2\x80\x99s 案例的集合。
为了访问案例,我们使用.allCases。欲了解更多信息,请点击https://developer.apple.com/documentation/swift/caseiterable
\nAlf*_*a07 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())")
}
Run Code Online (Sandbox Code Playgroud)
ada*_*com 17
这个问题现在变得容易多了.这是我的Swift 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
}
Run Code Online (Sandbox Code Playgroud)
前4.2
我喜欢这个在找到这个页面后放在一起的解决方案: Swift中的列表理解
它使用Int raws而不是Strings但它避免键入两次,它允许自定义范围,并且不硬编码原始值.
这是我原始解决方案的Swift 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
}
Run Code Online (Sandbox Code Playgroud)
Sen*_*ful 13
如果给enum 一个原始的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())
Run Code Online (Sandbox Code Playgroud)
然而,这看起来像一个相当常见的模式,如果我们可以通过简单地符合协议使任何枚举类型可枚举,那不是很好吗?好了Swift 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 }
}
Run Code Online (Sandbox Code Playgroud)
现在,只要您创建枚举(只要它具有Int原始值),您就可以通过符合协议使其可枚举:
enum Rank: Int, EnumerableEnum {
case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}
// ...
for rank in Rank.enumerate() { ... }
Run Code Online (Sandbox Code Playgroud)
如果您的枚举值不以0(默认值)开头,则覆盖该firstRawValue方法:
enum DeckColor: Int, EnumerableEnum {
case Red = 10, Blue, Black
static func firstRawValue() -> Int { return Red.rawValue }
}
// ...
let colors = Array(DeckColor.enumerate())
Run Code Online (Sandbox Code Playgroud)
最后西服类,包括更换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)
}
Run Code Online (Sandbox Code Playgroud)
编辑:
Swift 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
}
}
Run Code Online (Sandbox Code Playgroud)
ale*_*tro 12
更新为Swift 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
}
}
}
Run Code Online (Sandbox Code Playgroud)
它的更新代码雨燕2.2的形式@ Kametrixom是一个 swer
适用于Swift 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
}
}
}
Run Code Online (Sandbox Code Playgroud)
Joc*_*zer 12
斯威夫特 5 解决方案:
enum Suit: String, CaseIterable {
case spades = "?"
case hearts = "?"
case diamonds = "?"
case clubs = "?"
}
// access cases like this:
for suitKey in Suit.allCases {
print(suitKey)
}
Run Code Online (Sandbox Code Playgroud)
我发现自己在.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"]
Run Code Online (Sandbox Code Playgroud)
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 }
}
Run Code Online (Sandbox Code Playgroud)
称它为
print(Filter.allValues)
Run Code Online (Sandbox Code Playgroud)
印刷品:
[“工资”,“经验”,“技术”,“未利用”,“未利用的高价值”]
enum代表Intenum 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 }
}
Run Code Online (Sandbox Code Playgroud)
这样称呼它:
print(Filter.allValues)
Run Code Online (Sandbox Code Playgroud)
印刷品:
[0,1,2,3,4]
enum代表Stringenum 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"
}
}
}
Run Code Online (Sandbox Code Playgroud)
称它为
print(Filter.allValues)
Run Code Online (Sandbox Code Playgroud)
印刷品:
[“工资”,“经验”,“技术”,“未利用”,“未利用的高价值”]
编辑: Swift进化提案 SE-0194衍生的Enum案例集提出了这个问题的一个解决方案.我们在Swift 4.2和更新版本中看到它.该提案还指出了一些与此处已经提到的类似的解决方法,但仍然可能会有趣.
为了完整起见,我还会保留原帖.
这是基于@ Peymmankh的回答的另一种方法,适用于Swift 3.
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)
}
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
这个怎么样?
你可以尝试这样枚举
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]
Run Code Online (Sandbox Code Playgroud)