Removing duplicate elements from an array in Swift

后端 未结 30 2002
遥遥无期
遥遥无期 2020-11-22 00:07

I might have an array that looks like the following:

[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]

Or, reall

30条回答
  •  北恋
    北恋 (楼主)
    2020-11-22 00:43

    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
    

提交回复
热议问题