0

I have a loop that runs slowly. Is there a more efficient way of checking two arrays against each other in swift.

for photo in foodPhotos {
    for restaurant in self.restaurants {
        if (restaurant.objectId == photo.objectId){
            self.detailsForFoodPhotos.append(restaurant) // create array of ordered restaurants
            break // break if we find the matching restaurant
        }
    }
}

Explanation

For each element, the loop finds the objectId in the first array ( foodPhotos) that matches the objectId of an element in the second array (restaurants).

If the objectIds match, save the restaurants element in detailsForFoodPhotos. Continue until all foodPhotos have been checked.

Example:

Array of Photos: foodPhotos:

[ photo1, photo2, photo3 ]

Array of Restaurants restaurants:

[ restaurant1, restaurant2, restaurant3, restaurant4, restaurant3 ]

The loop checks which photo.objectID matches restaurant.objectID. Then creates a new array with the matching restaurants.

Output Array: detailsForFoodPhotos

[ restaurant3, restaurant1, restaurant2 ] 
// photo1.objectID == restaurant3.objectID
// photo2.objectID == restaurant1.objectID
// photo3.objectID == restaurant2.objectID
Onichan
  • 4,476
  • 6
  • 31
  • 60
  • 1
    "The loop checks if the `objectId` of each element in the first array: `foodPhotoRestaurantPFObjects` matches the second array" How an `objectId` match an _array_? Do you mean it is sufficient if the `objectID` is _in_ the array? – matt Jul 10 '15 at 17:29
  • 1
    store the objectIds of array `foodPhotoRestaurantPFObjects` in a set. that way, you won't need to iterate it again, and you are down to O(n) from O(n^2). i don't know the exact equivalent and syntax of `HashSet` in Swift but you can get help from here: http://stackoverflow.com/questions/24044190/how-to-create-array-of-unique-object-list-in-swift – tt_emrah Jul 10 '15 at 17:31
  • Are `objectID` values unique? – matt Jul 10 '15 at 17:38
  • @matt yes each `foodPhotoRestaurantPFObjects` has a unique `objectID`. But `restaurantPFObjects` may contain duplicates. Basically I want to remove the duplicates and match the order. – Onichan Jul 10 '15 at 17:40
  • "Basically I want to remove the duplicates and match the order." Oh, really???? That's new information (to me). Then what do you need `foodPhotoRestaurantPFObjects` for? Why isn't it sufficient to remove the duplicates from `restaurantPFObjects`? (And "match the order" of what, exactly?) (And one more question: are duplicate `restaurantPFObjects` absolutely duplicates, or different except for their object IDs?) – matt Jul 10 '15 at 17:42
  • Somehow the business logic totally masks the programming logic. After looking at the code and explanation for some time, I still don't understand what is or should be going on here. – Eiko Jul 10 '15 at 17:49
  • may I ask why the order of the foodPhotoRestauraunt objects should not change? – Josh Hamet Jul 10 '15 at 17:57
  • @JoshHamet Because the `foodPhoto` array is ordered based on number of votes. – Onichan Jul 10 '15 at 17:59
  • I don't see any use for the outer break condition, and the inner loop would be left to a find method on the array (if I understand that correctly). – Eiko Jul 10 '15 at 18:05

2 Answers2

2

I still think my other answer is the way to go. However, you haven't accepted it, and you've provided some actual data input and desired output, so here's a solution that produces it:

struct Photo {
    let objectID : Int
}
struct Restaurant {
    let objectID : Int
}

let foodPhotos = [Photo(objectID:1), Photo(objectID:2), Photo(objectID:3)]
let restaurants = [Restaurant(objectID:3), Restaurant(objectID:1), Restaurant(objectID:2)]
var d = [Int:Int]()
for (ix,r) in restaurants.enumerate() {
    d[r.objectID] = ix
}
var detailsForFoodPhotos = [Restaurant]()
for p in foodPhotos {
    if let ix = d[p.objectID] {
        detailsForFoodPhotos.append(restaurants[ix])
    }
}
// Now I'll prove that it worked
print(foodPhotos)
// [Photo(objectID: 1), Photo(objectID: 2), Photo(objectID: 3)]
print(restaurants)
// [Restaurant(objectID: 3), Restaurant(objectID: 1), Restaurant(objectID: 2)]
print(detailsForFoodPhotos)
// [Restaurant(objectID: 1), Restaurant(objectID: 2), Restaurant(objectID: 3)]

That requires just two simple loops; both are very fast. The key to the solution is the generation of an intermediate lookup table (dictionary), d, that hashes on the objectID to index into the second array.

matt
  • 515,959
  • 87
  • 875
  • 1,141
-1

you can use a dictionary to remove inner loop. Just index with element.objectId in the dictionary. If it is nil then not present else it is present. if you need code I can provide.

Md. Najmul Hasan
  • 605
  • 1
  • 6
  • 19