将所有枚举值作为数组获取

时间:2015-10-05 15:26:29

标签: arrays swift enums

我有以下枚举。

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

但是我收到了以下错误。

找不到类型&#39; GeneratorOf&#39;的初始化程序。接受类型&#39;(() - &gt; _)&#39;

的参数列表

我无法弄清楚如何解决这个问题。有帮助吗?或者请告诉我是否有更容易/更好/更优雅的方式来做到这一点。

谢谢。

13 个答案:

答案 0 :(得分:84)

对于Swift 4.2(Xcode 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)
}

对于Swift&lt; 4.2

不,您无法向enum查询其包含的值。见this article。您必须定义一个列出所有值的数组。还可以查看Frank Valbuena的clever solution

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

答案 1 :(得分:22)

Swift 4.2 引入了一个名为CaseIterable

的新协议
enum Fruit : CaseIterable {
    case apple , apricot , orange, lemon
}

当你符合时,你可以从像这样的enum案例中获得一个数组

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

答案 2 :(得分:14)

还有另一种方法,至少在编译时是安全的:

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

请注意,这适用于任何枚举类型(RawRepresentable与否)以及如果添加新案例,那么您将收到一个好的编译器错误,因为这会强制您使其保持最新状态。

答案 3 :(得分: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 :(得分:6)

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"]

答案 5 :(得分:1)

对于Swift 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)

答案 6 :(得分:1)

来自Sequence的灵感和几小时的尝试n错误。我终于在Xcode 9.1上获得了这个舒适漂亮的Swift 4方式:

 directed-link-breed [Ls L]

 to star
   ca
   nw:generate-star turtles Ls 100 ; using link breed
   [
      set color red
      fd random 15
      set shape "circle"
      ask links [set color yellow]
   ]

   nw:generate-star turtles Ls-to 100 ; it does not work
end

用法:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="557.0" prefWidth="1012.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <SplitPane fx:id="splitPane" dividerPositions="0.5" layoutX="-8.0" layoutY="35.0" mouseTransparent="true" prefHeight="529.0" prefWidth="1027.0" style="-fx-background-color: #EEEEEE;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="28.0">
        <items>
            <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
               <children>
                  <ListView fx:id="list_todo" layoutY="-8.0" prefHeight="527.0" prefWidth="584.0" style="-fx-padding: 3px;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
               </children>
            </AnchorPane>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
               <children>
                  <ListView fx:id="list_done" layoutY="14.0" prefHeight="527.0" prefWidth="420.0" style="-fx-padding: 3px;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
               </children></AnchorPane>
        </items>
      </SplitPane>
      <MenuBar prefHeight="30.0" prefWidth="1012.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <menus>
          <Menu fx:id="menu_cambiarUser" mnemonicParsing="false" text="Cambiar usuario" />
          <Menu mnemonicParsing="false" text="Edit">
            <items>
              <MenuItem mnemonicParsing="false" text="Delete" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Help">
            <items>
              <MenuItem mnemonicParsing="false" text="About" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
   </children>
</AnchorPane>

输出:

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

答案 7 :(得分: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)
}

答案 8 :(得分:1)

要获取出于功能目的的列表,请使用表达式EnumName.allCases,该表达式返回一个数组,例如

EnumName.allCases.map{$0.rawValue} 
鉴于EnumName: String, CaseIterable

将为您提供字符串列表

注意:使用allCases代替AllCases()

答案 9 :(得分:0)

如果您的枚举是增量的并且与数字相关联,则可以使用映射到枚举值的数字范围,如下所示:

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

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

对于与字符串或数字以外的任何其他内容相关的枚举,这并不适用,但如果是这样的话,效果会非常好!

答案 10 :(得分:0)

Swift 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枚举上的

CaseIterable将返回该元素的Collection

var myEnumArray = EstimateItemStatus.allCases

有关CaseIterable

的更多信息

答案 11 :(得分:0)

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

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

[“待处理”,“暂停”,“完成”]

答案 12 :(得分:0)

扩展枚举以创建allValues。

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