enum EnumType {
case WithString(String)
}
var enums = [EnumType]()
enums.append(EnumType.WithString("A"))
enums.append(EnumType.WithString("B"))
enums.append(EnumType.WithString("C"))
enums.append(EnumType.WithString("D"))
enums.append(EnumType.WithString("E"))
enums.append(EnumType.WithString("F"))
如何过滤我的
enums
数组以查找关联值等于 C
的数组。我需要使用什么谓词?
过滤器函数既可以作为数组上的全局函数调用,也可以作为实例方法调用(我更喜欢后者,因为它更面向对象)。
它接受一个带有一个参数(正在评估的元素)的闭包,该参数返回一个布尔值(指示该元素是否符合所需条件)。
由于这是一个在明确情况下的简单闭包,因此可以使用缩写形式。
我想其他“With”情况会添加到您的枚举中,因此您可以使用类似的内容:
let filteredArray = enums.filter {
switch $0 {
case .withString(let value):
return value == "C"
default:
return false
}
}
这应该可以解决你的示例中的问题。
正如有人已经提到的,对于 Swift > 2.0,有 if case 语句可用:
enums.filter {
if case .WithString("C") = $0 {
return true
}
return false
}
但是,它看起来不太好,特别是如果您要再次重复相同的逻辑。这里我们能做的就是让 EnumType 符合 Equatable:
extension EnumType: Equatable {
}
func ==(lhs: EnumType, rhs: EnumType) -> Bool {
switch (lhs, rhs) {
case (.WithString(let lStr), .WithString(let rStr)):
return lStr == rStr
}
}
现在您可以:
enums.filter { $0 == .WithString("C") }
您可以尝试向枚举添加一个带有计算属性的简单扩展,并过滤该属性:
extension EnumType {
var isC: Bool {
switch self {
case .WithString(let message): return message == "C"
default: return false
}
}
}
此后,您可以像往常一样简单地使用过滤:
enums.filter { $0.isC }
var filteredArray = enums.filter { element in
switch element {
case EnumType.WithString(let string):
return string == "A"
default:
return false
}
}
这可能可以通过 Swift 2.0 绑定
if
语句中的关联值来简化。
受到@Jessy和SwiftLee的启发,这是我的解决方案:
// -----------------------
// CaseReflectable
// -----------------------
// designed for enums only
// (use it on other types not recommended)
protocol CaseReflectable {}
// default behaviors.
extension CaseReflectable {
/// case name
var caseName: String {
let mirror = Mirror(reflecting: self)
// enum cases:
// - normal case: no children
// - case with associated values: one child (with label)
guard let label = mirror.children.first?.label else {
return "\(self)" // normal case
}
// case with associated values
return label
}
/// associated values
var associatedValues: Any? {
// if no children, a normal case, no associated values.
guard let firstChild = Mirror(reflecting: self).children.first else {
return nil
}
return firstChild.value
}
}
// --------------------------
// custom operator ~=
// --------------------------
/// match enum cases with associated values, while disregarding the values themselves.
/// usage: `Enum.enumCase ~= instance`
func ~= <Enum: CaseReflectable, AssociatedValue>(
// an enum case (with associated values)
enumCase: (AssociatedValue) -> Enum, // enum case as function
// an instance of Enum
instance: Enum
) -> Bool
{
// if no associated values, `instance` can't be of `enumCase`
guard let values = instance.associatedValues else { return false }
// if associated values not of the same type, return false
guard values is AssociatedValue else { return false }
// create an instance from `enumCase` (as function)
let case2 = enumCase(values as! AssociatedValue)
// if same case name, return true
return case2.caseName == instance.caseName
}
// ------------
// Enum
// ------------
// enum with associated values
// (conforms to `CaseReflectable`)
enum Enum: CaseReflectable {
case int(Int)
case int2(Int)
case person(name: String, age: Int)
case str(String)
}
// ------------
// main
// ------------
let a: Enum = .int(3)
Enum.int ~= a // true
Enum.int2 ~= a // false
let joe = Enum.person(name: "joe", age: 8)
Enum.person ~= joe // true
Enum.int ~= joe // false
// array of enum cases
let items: [Enum] = [
.int(1), .str("hi"), .int(2)
]
// filter enum cases
let filtered = items.filter { Enum.int ~= $0 }
print(filtered) // [Enum.int(1), Enum.int(2)]
您可以通过实现
Equatable
协议来实现更可重用的东西:
enum EnumType {
case WithString(String)
}
extension EnumType: Equatable {
static func ==(lhs: EnumType, rhs: String) -> Bool {
switch lhs {
case .WithString(let value):
return value == rhs
}
}
}
EnumType.WithString("F") == "A" // false
EnumType.WithString("F") == "F" // true