Search code examples
arraysswiftstructcontainsstring-comparison

Check if struct string array contains elements of another string array


I created an array of struct elements. These structs get to contain an array of strings. I want to check if these strings happen to be in another array of strings.

How can I do that or what tools should I look into?

I found that I can use a command called "Set", but it doesn't seem to work arrays within a struct.

import UIKit

// Define structure
struct Drink {
    var name: String
    var content: Array<String>
    var amount: Array<Int>
    var desc: String
}

// Define drinks
var mojito = Drink(name: "Mojito", content: ["Rum","Club soda"], amount: [4,20], desc: "Summer drink")
var vodkaJuice = Drink(name: "Vodka juice", content: ["Vodka","Juice"], amount: [4,20], desc: "Cheap alcohol")
var list = [mojito,vodkaJuice]

// Define what ingredients you have
var stock = ["Gin", "Vodka", "Juice", "Club soda"]

How do I make a list of drinks I can make from what I have?


Solution

  • Use a Set instead of an array so you can simply do a subset check:

    import UIKit
    
    // Define structure
    struct drink {
        var name : String
        var content : Set<String> // we use a Set instead
        var amount : Array<Int>
        var desc : String
    }
    
    // Define drinks
    var mojito = drink(name: "Mojito", content: ["Rum","Club soda"], amount: [4,20], desc: "Summer drink")
    var vodkaJuice = drink(name: "Vodka juice", content: ["Vodka","Juice"], amount: [4,20], desc: "Cheap alcohol")
    var list = [mojito,vodkaJuice] 
    
    // Define what ingredients you have
    var stock = ["Gin", "Vodka", "Juice", "Club soda"]
    
    // find all instances of drinks where their contents
    // are subsets of what you have in stock
    let drinks = list.filter { $0.content.isSubset(of: stock) }
    

    The importance of using sets instead of "for-loops inside for-loops" is performance. Set uses an internal hash table to look up an item in an extremely fast fashion. So the overall complexity of your lookups would be O(N.logM) for N items in list and M items in stock.

    If you had done it with for loops, its complexity would be O(N.M) which could take longer and consume more battery depending on the number of items you have.

    That doesn't mean you should always use sets though. Sets have tradeoffs. They bring in performance but their initial construction is slower and they don't support duplicate items. Use them only in specific cases like this. Never use sets because "they are faster", use them when they solve your specific problem.

    I strongly recommend skimming over those additional data structures provided by Swift's runtime so you'll know which one to use and when.