I might have an array that looks like the following:
[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
Or, reall
Think like a functional programmer :)
To filter the list based on whether the element has already occurred, you need the index. You can use enumerated
to get the index and map
to return to the list of values.
let unique = myArray
.enumerated()
.filter{ myArray.firstIndex(of: $0.1) == $0.0 }
.map{ $0.1 }
This guarantees the order. If you don't mind about the order then the existing answer of Array(Set(myArray))
is simpler and probably more efficient.
UPDATE: Some notes on efficiency and correctness
A few people have commented on the efficiency. I'm definitely in the school of writing correct and simple code first and then figuring out bottlenecks later, though I appreciate it's debatable whether this is clearer than Array(Set(array))
.
This method is a lot slower than Array(Set(array))
. As noted in comments, it does preserve order and works on elements that aren't Hashable.
However, @Alain T's method also preserves order and is also a lot faster. So unless your element type is not hashable, or you just need a quick one liner, then I'd suggest going with their solution.
Here are a few tests on a MacBook Pro (2014) on Xcode 11.3.1 (Swift 5.1) in Release mode.
The profiler function and two methods to compare:
func printTimeElapsed(title:String, operation:()->()) {
var totalTime = 0.0
for _ in (0..<1000) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
totalTime += timeElapsed
}
let meanTime = totalTime / 1000
print("Mean time for \(title): \(meanTime) s")
}
func method1(_ array: Array) -> Array {
return Array(Set(array))
}
func method2(_ array: Array) -> Array{
return array
.enumerated()
.filter{ array.firstIndex(of: $0.1) == $0.0 }
.map{ $0.1 }
}
// Alain T.'s answer (adapted)
func method3(_ array: Array) -> Array {
var uniqueKeys = Set()
return array.filter{uniqueKeys.insert($0).inserted}
}
And a small variety of test inputs:
func randomString(_ length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..
Gives as output:
Mean time for method1 on shortIntList: 2.7358531951904296e-06 s
Mean time for method2 on shortIntList: 4.910230636596679e-06 s
Mean time for method3 on shortIntList: 6.417632102966309e-06 s
Mean time for method1 on longIntList: 0.0002518167495727539 s
Mean time for method2 on longIntList: 0.021718120217323302 s
Mean time for method3 on longIntList: 0.0005312927961349487 s
Mean time for method1 on longIntListManyRepetitions: 0.00014377200603485108 s
Mean time for method2 on longIntListManyRepetitions: 0.0007293639183044434 s
Mean time for method3 on longIntListManyRepetitions: 0.0001843773126602173 s
Mean time for method1 on longStringList: 0.007168249964714051 s
Mean time for method2 on longStringList: 0.9114790915250778 s
Mean time for method3 on longStringList: 0.015888616919517515 s
Mean time for method1 on longMegaStringList: 0.0525397013425827 s
Mean time for method2 on longMegaStringList: 1.111266262292862 s
Mean time for method3 on longMegaStringList: 0.11214958941936493 s