1

I have an array of restaurantsIds in a specific order. I make a network call to get Restaurants for each one of these ids. I am returned with all the Restaurants in the order that they are returned. Restaurants is a custom class and one of the properties is restaurantId. I want to sort the returned Restaurants in the order of the IDs. How would I do that? I think I am supposed to use the sorted function. How would I go upon doing this? There can be duplicate restaurants so I can't use a dictionary to do it. If is is a duplicate restaurant that is returned then it doesn't really matter which instance of that restaurants comes first.

var restaurantIds = [947575, 858914, 255964]
var returnedRestaurant:[Restaurant]!
returnedRestaurant.sorted { (rest1, rest2) -> Bool in
        //How would I go about matching rest1 and rest2 to the list of restaurantIds above?
        rest1.productID......
    }
2
  • That would sort it numerically, I want to sort it by the custom order that is in the restaurantIds array. Commented Jul 30, 2017 at 17:56
  • You're making a "network call" but how? Are you requesting them one by one, are you requesting them all at once and getting a list back, do they get returned with the id as part of the data? We really need more information or we're just guessing at a solution. Commented Jul 30, 2017 at 19:01

3 Answers 3

3

If I understand correctly you wish to sort your array by the order the IDs occur in restaurantIds.

Array provides the method index(of:) which given an element returns the index of its first occurrence in the array. For example restaurantIds.index(of:858914) would return 1.

You can use the result of index(of:) as your sorting key. I.e. In your sorting function the value you need to compare for rest1 would be restaurantIds.index(of: rest1.productID).

HTH

Addendum

@vacawama raises and issue with is both correct in principle but may be wrong in practice... Using restaurantIds.index(of: rest1.productID) a lot is not good for performance and for longer lists of restaurant IDs you may need to optimise by avoiding the repeated index(of:) calls. However for short lists any performance change (it could be a win or lose) is probably insignificant and optimisation just complicates the code.

TL;DR: YMMV, KISS, beware premature optimisation, your call.

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

3 Comments

I think this is what OP is looking for. Rest of the answers wont work.
For anybody now reading this, @adev was correct at the time. Now vacawama's solution also works and is a different take on the same idea. Take your pick.
Probably putting in an ordered set may help with index issue assuming ids are unique.
2

Create a dictionary that maps the restaurantID to the order of that ID. You can then use that to sort your array:

var restaurantIds = [947575, 858914, 255964]

// Create a dictionary that maps the order of the restaurantID
var order = [Int: Int]()
for (idx, rid) in restaurantIds.enumerated() {
    order[rid] = idx
}

var returnedRestaurant:[Restaurant]!

returnedRestaurant.sort { (rest1, rest2) -> Bool in

    // look up the order for the restaurant id.  If the id is missing, use
    // Int.max to put that restaurant at the end of the array

    let order1 = order[rest1.id] ?? Int.max
    let order2 = order[rest2.id] ?? Int.max

    return order1 < order2
}

If you have more than just a few restaurant IDs, this is likely more efficient than repeatedly using index(of:) to figure out the mapping. The larger your restaurant array, the more times index(of:) is called (because sort is O(n log n)) so the number of calls to index(of:) grows rapidly as the size of the restaurant array increases. index(of:) is an O(n) operation based upon the size of the id array. The larger your id array, the slower index(of:) becomes.

8 Comments

"This is more efficient..."? In the example restaurantIDs is short, it could of course be longer but given its a list of IDs is an iOS app to look up in a database we can probably guess its not that large. A dict requires dynamic allocation and hash calculations on insertion and lookup. Array's index(of:) probably needs to offset calculations (might just iterate) and will average n/2 comparisons. Either approach could be faster, data dependent, but is it really important? Are you sure this isn't premature optimisation? (I admit, I considered a dict, we all get tempted to not KISS ;-))
@CRD, there are advantages both ways. If OP really only has 3 ids, then a dictionary is overkill. The list of restaurant IDs is known ahead of time, so the dictionary can be created at that time instead of waiting for the restaurants to be read. In a sort, the same lookup will happen repeatedly, so n/2 adds up. I don't think this is premature optimization. It's thinking about an algorithm that scales nicely. With 6-digit restaurant ids, there are probably more than 3.
Edit is good, but you should probably still have a "probably" in there ;-)
I know this will eventually be more efficient than index(of:). The only remaining question in my mind is where the break even point is. If the dictionary can be created ahead of time, then the break even point is even lower.
We're dancing here, I say "probably", you say "eventually" ;-) You got my original point, however poorly expressed, nice talking to you.
|
0

One way to do it is to iterate through your restaurantIds array using flatMap and return the first element from your returnedRestaurant array whose id matches the id at the current index in restaurantIds. This function returns a new sorted array and doesn't mutate the returnedRestaurant array in place.

let sortedRestaurants = restaurantIds.flatMap{ id in
    returnedRestaurant.filter{$0.restaurantId == id }.first
}

3 Comments

If you use a flatmap function on restaurantIds it would flatten the array of restaurantIds but we don't want to flatten the array, we just want to sort the returnedRestaurant in the order based on the restaurantIds array using the id within each Restaurant. I haven't tried this yet but if you think it will work I will give it a try.
As long as you don't have duplicate restaurantIds this works. If you do have duplicateIds, then this drops all but the first restaurant found.
@vacawama you are right, I assumed ids to be unique. But this solution can easily be modified to work with repeating ids as well.

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.