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

How to filter my enums array to find the one with associated value equal C. What predicate do I need to use?

2
  • What's the purpose of an enum with no enumerated values? You're just creating an array/list of String elements. However, filtering an array is easy: let filteredArray = array.filter { $0 matches condition } Commented Jun 22, 2015 at 7:26
  • I will use it in a more complex example:-) but the essence is in the SIMPLEST example Commented Jun 22, 2015 at 7:27

6 Answers 6

26

The filter function can either be invoked as a global function over an array, or as an instance method (I prefer the later as it is more OO).

It accepts a closure with one parameter (the element being evaluated) that return a boolean (indicating whether the element matches the required condition).

Since it's a simple closure in a clear situation it's ok to use the abbreviated form.

I guess that other "With" cases would be added to your enum, so you could go with something like:

let filteredArray = enums.filter { 
    switch $0 {
      case .withString(let value):
        return value == "C"
      default:
        return false
    }
 }

That should do the trick in your example.

Sign up to request clarification or add additional context in comments.

1 Comment

No, it is not the trick... It is not example with rawValue.
11

As someone already mentioned, for Swift > 2.0 there's if case statement available:

enums.filter {
  if case .WithString("C") = $0 {
    return true
  }
  return false
}

But, it doesn't look nice, especially if you are going to repeat same logic again. What we can do here is to make EnumType conform to Equatable:

extension EnumType: Equatable {
}

func ==(lhs: EnumType, rhs: EnumType) -> Bool {
    switch (lhs, rhs) {
    case (.WithString(let lStr), .WithString(let rStr)):
        return lStr == rStr
    }
}

And now you can just:

enums.filter { $0 == .WithString("C") }

Comments

2

You could try adding a simple extension with a computed property to your enum and filter to that property:

extension EnumType {
  var isC: Bool {
    switch self {
    case .WithString(let message): return message == "C"
    default: return false
    }
  }
}

After this, you could simpy use the filtering as usual:

enums.filter { $0.isC }

Comments

0
var filteredArray = enums.filter { element in
    switch element {
    case EnumType.WithString(let string):
        return string == "A"
    default:
        return false
    }
}

This can probably be simplified with Swift 2.0 binding of assosciated values in if statements.

Comments

0

Inspired by @Jessy and SwiftLee, here is my solution:

// -----------------------
//     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)]

Comments

0

You can achieve something more reusable by implementing Equatable protocol:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.