0

I'm trying to figure out a way to retrieve all elements in a nested enum from an array. The way I built my nested enum as follows:

enum ItemType: Hashable {
    case sword(Swords) 
    case shield(Shields)  
    case armor(Armors) 
}

enum Swords: String, CaseIterable {
    case Sabre = "Sabre"
    case Xiphos = "Xiphos"
    case Broadsword = "Broadsword"
}

enum Shields: String, CaseIterable {
    case Buckler = "Buckler"
    case HeaterShield = "Heater Shield"
    case KiteShiled = "Kite Shield"

}

enum Armors: String, CaseIterable {
    case StudArmor = "Stud Armor"
    case Chainmail = "Chainmail"
    case PlateArmor = "Plate Armor"
}

Now I have an array that contains some of the elements from the ItemType enum:

let loots: [ItemType] = [
    .sword(.Xiphos),
    .sword(.Broadsword), 
    .sword(.Sabre),
    .armor(.StudArmor), 
    .armor(.Chainmail),
    .shield(.Buckler), 
    .shield(.HeaterShield)
]

Is there a way to get all elements under ItemType.sword into another array? I'm thinking along the line of: (obviously it doesn't work)

let item = loots.first(where: {$0 == ItemType.sword}) 

How can I achieve my goal? Or do I have to reconstruct my Enums in a different way?

Please let me know.

Thank you in advance.

1

1 Answer 1

0

You can add a computed property to your enum ItemType to check if it is a sword or not:

extension ItemType {
    var isSword: Bool {
        switch self {
        case .sword:
            return true
        default:
            return false
        }
    }
}

or if you prefer if case instead of switch:

extension ItemType {
    var isSword: Bool {
        if case .sword = self { return true }
        return false
    }
}

Them you can simply get the first item where isSword or filter them:

let item = loots.first(where: \.isSword) // sword(.Xiphos)

let items = loots.filter(\.isSword) // [{Xiphos}, {Broadsword}, {Sabre}]

Note that it is Swift naming convention to name all your enumeration cases starting with a lowercase letter.

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

6 Comments

Thank you so much! This worked great. However, I do have a follow up question. How do I pass something like .isSword as a parameter? As in some cases where I might want to filter for ItemType.shield or ItemType.armor.
"How do I pass something like .isSword as a parameter?" Not sure what you mean but I guess you are asking how to pass it in a closure. where: \.isSword can also be written as { $0.isSword }. If you need isShield or isArmor you need to add those computed properties as well and filter { $0.isArmor || $0.isShield }. Another option is to create an isArmorOrShield property and use it as a keyPath syntax.
What I wanted is to call a func and pass in a parameter to be used as the criteria for array filter. Func filterItem(parameter) { let items = loots.filter(parameter)} Hope I made myself clear.
@Bob If you need a func you can add predicate: (ItemType) -> Bool to your method signature. func filterItem(predicate: (ItemType) -> Bool) and then loots.filter(predicate)
I've figured it out: Func filterItem(myFilter: @escaping (ItemType) -> Bool). This way, I can call it using: filterItem(myFilter: {$0.isArmor}). Thanks again for all your help!
|

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.