Reputation: 5330
I have an array as a list of numbers. In another smaller array I hold some numbers (in a different order) and I'd like to filter my first array using the values in the second array.
My arrays:
let allNumbers = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200]
let someNumbers = [100, 90, 120, 200] // unordered
When I use filter
method or loop through the values of the first array, I can get the correct values but the order of the elements is not same with my second array but the first -naturally.
Method 1: filter
method, losing order
let filtered = allNumbers.filter { someNumbers.contains($0) } // Runs 17 times
print(filtered) // "[90, 100, 120, 200]" (wrong order)
Method 2: Looping through first array, losing order
var filteredWithLoop: [Int] = []
for number in allNumbers { // Runs 16 Times
if someNumbers.contains(number) {
filteredWithLoop.append(number)
}
}
print(filteredWithLoop) // "[90, 100, 120, 200]" (wrong order)
Hack: I can work this around by filtering the first array when I'm looping through the second, like this:
var filteredUglyWay: [Int] = []
for number in someNumbers {
if let alone = (allNumbers.filter { $0 == number }).first { // Runs 4 * 16 Times
filteredUglyWay.append(alone)
}
}
print(filteredUglyWay) // "[100, 90, 120, 200]" (correct order)
But this feels more like a hack rather than a solution to me especially considering that the loop-ish filter method is called in a loop.
Is there a better approach for this or is this just how it's supposed to be?
Important note: The first array is actually a representation to make the situation more understandable. In my real implementation, first array is holding some objects and the second array is just the ID list of some objects (like favorites of the user) so each time I fetch the whole data, I am trying to filter the favorite objects according to this ID list.
Upvotes: 1
Views: 3195
Reputation: 1
You can do this:
let filtered = someNumbers.filter { allNumbers.contains($0) }
print(filtered) // Prints [100, 90, 120, 200]
It's probably less efficient when allNumbers is much larger than someNumbers, but if efficiency isn't an issue here, it seems like this is the most neat solution to me.
Upvotes: 0
Reputation: 26036
A possible solution: Filter, then sort.
let filtered = allNumbers.filtered({ someNumbers.contains($0) })
let filteredAndSorted = filtered.sorted(by: { someNumbers.index(of: $0)! < someNumbers.index(of: $1)! })
Side note, since filtered
is composed of data only in someNumbers
, the fore unwrap shouldn't create a crash.
Upvotes: 3
Reputation: 2916
why not to try updated method 2
Method 2 UPDATED: Looping through second array
var filteredWithLoop: [Int] = []
for number in someNumbers { // Runs 4 Times
if allNumbers.contains(number) {
filteredWithLoop.append(number)
} // IF OBJECT IS NOT THERE IN FIRST ARRAY IT WILL BE AUTOMATICALLY DISCARDED
}
print(filteredWithLoop) // "[100, 90, 120, 200]" (proper order)
Upvotes: 0