An introduction to the easy way
We have a couple of options when it comes to replacing a range of values within an array, and one might call them the hard way and the easy way. Starting with the "hard way", there is a method called
replaceRange:with:
var array = [1,2,3,4,5,6,7,8,9,10]
array.replaceRange(Range(start: array.startIndex.advancedBy(1),end: array.startIndex.advancedBy(2)), with: [11,11]) // [1, 11, 11, 3, 4, 5, 6, 7, 8, 9, 10]
Using this method we must supply a Range
to begin with and then a collection of the type we are working with to the with: argument. It needn't be as convoluted as the first example, however, because we can do the following:
var array = [1,2,3,4,5,6,7,8,9,10]
array.replaceRange(Range(1...2), with: [11,11]) // [1, 11, 11, 3, 4, 5, 6, 7, 8, 9, 10]
and we can go even further in our code reduction:
var array = [1,2,3,4,5,6,7,8,9,10]
array.replaceRange(1...2, with: [11,11]) // [1, 11, 11, 3, 4, 5, 6, 7, 8, 9, 10]
But the ultimate simplification is to use subscripting ("the easy way"):
var array = [1,2,3,4,5,6,7,8,9,10]
array[1...2] = [11,11] // [1, 11, 11, 3, 4, 5, 6, 7, 8, 9, 10]
A few questions follow.
What happens if the length of the range we supply is larger than the number of values we pass?
The whole range is replaced by the values and the total length of the array shrinks. So if you have a range that is two values in length and you supply one value, the first value in the range is replaced and the second is removed. Here's an example:
var array = [1,2,3,4,5,6,7,8,9,10]
array[1...3] = [11] // [1, 11, 5, 6, 7, 8, 9, 10]
What happens if the length of the range we supply is shorter than the number of values we pass?
If the range is shorter than the number of values then the array grows, because the additional values are inserted in the same way as they would be if you were to use
insert:atIndex: or
insertContentsOf:at:.
var array = [1,2,3,4,5,6,7,8,9,10]
array[1...3] = [11,11,11,11,11] // [1, 11, 11, 11, 11, 11, 5, 6, 7, 8, 9, 10]
Does this mean there is a way to use the "easy way" as an insert method?
Yes, you can utilise the half-open range operator (
..<):
var array = [1,2,3,4,5,6,7,8,9,10]
array[1..<1] = [11] // [1, 11, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Is there a way to use the "easy way" as a delete method as well then?
Yes:
var array = [1,2,3,4,5,6,7,8,9,10]
array[1...1] = [] // [1, 3, 4, 5, 6, 7, 8, 9, 10]
array[3...6] = [] // [1, 3, 4, 9, 10]
What happens if the range we wish to replace goes beyond the length of the array?
Crash! Even if the range starts within the boundaries of the array:
var array = [1,2,3,4,5,6,7,8,9,10]
array[9...10] = [11,11] // Crash
So how do we append using the "easy way"?
You can use subscripting to append a value in the following way:
var array = [1,2,3,4,5,6,7,8,9,10]
array[10..<10] = [11] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
And if you wish to append a collection of elements, no need to use
appendContentsOf: simply write
var array = [1,2,3,4,5,6,7,8,9,10]
array[10..<10] = [11,12,13] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
What we are doing here is taking the endIndex of the array to make our half-open array, so really it would be clearer to write:
array[array.endIndex..<array.endIndex] = [11,12,13] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Conclusion
While replacing a range is less verbose using subscripting, it could well be argued that
removeRange: and
appendContentsOf: provide a better statement of intent than the examples above. Especially when we need only write for example:
array.removeRange(1...3)
and
array.appendContentsOf([11,12,13])
In the final case, in particular, when we consider the
array.endIndex...<array.endIndex code provided above, subscripting is both more verbose and less clear. And although we can improve things a little using an extension
extension Array {
var appendPosition: Range<Int> {
return self.endIndex..<self.endIndex
}
}
array[array.appendPosition] = [11,12,13] // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
it looks like we are finding excuses not to use the append method available to us. But both options exist, subscripting and instance methods, and in some situations the flexibility of subscripting will determine its use, where we do not discriminate for example between appending, inserting, deleting and so on, and in other situations descriptiveness will rule.
The second example of "easy way" delete method. It should be :
ReplyDeletearray[3...6] = [] // [1, 3, 8, 9, 10]