1

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.

7
  • Method1/2, what about inversing the two arrays? let filtered = someNumbers.filter { allNumbers.contains($0) } Commented Jul 13, 2018 at 12:30
  • Line1: let combined = zip(self.leavelistdatearr, self.leavelistnamearr).sorted {$0.0 < $1.0} print(combined) // use map to extract the individual arrays Line2: let sorted1 = combined.map {$0.0} Line3: let sorted2 = combined.map {$0.1} Line4: self.leavelistdatearr = sorted1 Line5: self.leavelistnamearr = sorted2 Commented Jul 13, 2018 at 12:31
  • @Larme Edited the question, the first array is actually a representation. In my code it is holding some custom objects instead of plain numbers so I am trying to filter those objects according to my second (let's say, favorites) array. Commented Jul 13, 2018 at 12:36
  • 1
    stackoverflow.com/questions/39273370/… Commented Jul 13, 2018 at 12:44
  • 1
    @Larme To satisfy the Swift 4 compiler, it's actually like this: let final = filtered.sorted(by: { someNumbers.index(of: $0)! < someNumbers.index(of: $1)! }). Thanks for the idea, could you please post this as an answer so that I can approve? Commented Jul 13, 2018 at 12:57

3 Answers 3

3

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.

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

Comments

0

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)

Comments

0

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.

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.