1

I'm a Swift newbie and I'm trying to get to grips with the following data structure. I have an array (categories) of category structs. Each category struct contains an array of business structs stored as a value on the property items. I'm not sure how to represent this kind of thing but hopefully this pseudo-code makes it a little bit clearer:

categories: [category]
   - category: Struct
        .categoryId: Int
        .items: [business]
            - business: Struct
               .busId: Int
            - business: Struct
               .busId: Int
   - category: Struct
        .categoryId: Int
        .items: [business]
            - business: Struct
               .busId: Int
            - business: Struct
               .busId: Int

Given a busId I'm trying to return a matching business Struct and the categoryId in which it is contained. I've tried using FlatMap and Map but I'm going round in circles trying to unwrap and filter this data structure.

Any pointers/advice about approaches to take would be great.

9
  • Could you write the structure in swift literal syntax for us to more easily use? Commented Jun 14, 2016 at 19:09
  • @AMomchilov - I'm happy to do anything that helps but I'm afraid I don't know what you mean :-( Shall I post the Struct classes? (I was trying to keep it simple :-p ) Commented Jun 14, 2016 at 19:10
  • By Swift literal syntax as in anArray = [1, 2, 3], aDict = ["a" : 1], etc. Commented Jun 14, 2016 at 19:12
  • @James: Can a Business appear in more then 1 Category? Commented Jun 14, 2016 at 19:22
  • @appzYourLife That's a gotcha I thought of earlier. For this use case I think it'll be fine to use the first category in which they appear. Commented Jun 14, 2016 at 19:24

2 Answers 2

3

Given a Business struct defined like this

struct Business {
    let busID: Int
}

A Category like this

struct Category {
    let categoryID: Int
    let business: [Business]
}

And a list of Category

let categories = [
    Category(categoryID: 0, business: [Business(busID:0)]),
    Category(categoryID: 1, business: [Business(busID:1), Business(busID:2)])
]

We can extract the categoryID and the Business having a given Int

func search(businessID: Int, categories: [Category]) -> (categoryID: Int, business:Business)? {
    let res = categories.reduce([Int:Business]()) { (res, category) ->  [Int:Business] in
        guard res.isEmpty else { return res }
        var res = res
        if let business = (category.business.filter { $0.busID == businessID }).first {
            res[category.categoryID] = business
        }
        return res
    }

    guard let categoryID = res.keys.first, business = res[categoryID] else  { return nil }
    return (categoryID, business)
}

Example

enter image description here

Update

This is a shorter version which does not use reduce

func search(businessID: Int, categories: [Category]) -> (categoryID: Int, business:Business)? {
    guard let
        category = (categories.filter { $0.business.contains { $0.busID == businessID } } ).first,
        business = (category.business.filter { $0.busID == businessID } ).first
    else { return nil }
    return (category.categoryID, business)
}
Sign up to request clarification or add additional context in comments.

5 Comments

Wow! Thank you so much. I was busy working with @AMomchilov's great answer below when this arrived. This is exactly what I was after. However, there's lots in your answer I wasn't aware of (e.g. I didn't know about reduce). I'll definitely try to learn more about reduce, map and flatMap as it seems to be holding me back. Thanks again for such an amazing answer :-)
@James: If you want to avoid the reduce you can use the new version of search I just added to my answer.
@James for the record, there's nothing reduce, map, flatMap and filter do that for loops can't. They just make it simpler in many (but not all!) cases
@AMomchilov: I agree: they are simply high level tools.
Yay!! I've got it working beautifully using the original (reduce) answer. Thanks for your comments about reduce etc - I'm going spend more time learning about this stuff as I clearly have got my brain in a muddle about it. Thank to you and @AMomchilov for taking the time to help out...I'm very grateful indeed.
1

How's this?

categories.filter{category in //filter the categories as the final result
    category.items //get the Businesses in the category
            .map{$0.busId} //get the busIds of the Businesses
            .contains(desiredBusinessID) //keep iff the desired busId is present
}

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.