Search code examples
swiftsortingcopy-on-write

How do I achieve an in-place sort on a sub range of elements in an Array<T> in swift?


The standard sort methods for the Array type does not have a variant in which the region of the array to be sorted can be narrowed. Using an ArraySlice does not result in the original data getting sorted due to the copy-on-write semantics.

Do I have to write a new sort implementation to achieve an in-place sort on a subrange of an Array? Or is there an ugly way to create a second Array that aliases the desired element range from the original array?


Solution

  • The subscript operation that takes a range returns a mutable value. If you directly invoke a mutating method on it, it will mutate the original array in place:

    var numbers = [3,5,2,4,1]
    numbers[1..<4].sort()
    print(numbers) // [3, 2, 4, 5, 1]
    

    As of Swift 4.2, I think this is no more efficient than making a temporary copy of the slice (Source: forum post 1, forum post 2. These posts talk about all kinds of slicing operations incl. ones that change the length of the source collection, but it should be the same for in-place sorting.)

    There've been a lot of under the hood changes for the upcoming Swift 5 release that aim to make this more efficient (background: ownership manifesto). In Swift 5, a setter (like a mutating subscript) can be modeled as a coroutine, which would allow to perform this kind of operation in place. But I'm not 100% sure if this will be the case in Swift 5.0.