Like this:
let str = "1234567890"
let arr = Array<Double>(count: countElements(str), repeatedValue: 0.0)
When I need to lookup a value in the array, I have a String.Index and need to convert it to an Int every time I need to lookup a value, like this:
for var i = str.startIndex; i < str.endIndex; i = i.successor() {
println(arr[distance(str.startIndex, i)])
}
It would be nice if I could use the String.Index as the index in the array also, like this:
extension Array {
subscript (index: String.Index) -> T {
set {
self[distance("".startIndex, index)] = newValue
}
get {
return self[distance("".startIndex, index)]
}
}
}
But a String.Index always stays associated with the string that it is derived from. You can check this with the following code:
let str1 = "1234567890"
let str2 = "12"
var j = str2.startIndex
var c = str[j]
j = j.successor()
c = str[j]
j = j.successor()
c = str[j]
Thus the first implementation of the String.Index accessor above will not work. The first variable in the 'distance' call will immediately throw an EXC_BAD_INSTRUCTION when we try to increment beyond String.startIndex.
To my surprise however, it is possible to use multiple parameters in a subscript accessor, like this:
extension Array {
subscript (string: String, index: String.Index) -> T {
set {
self[distance(string.startIndex, index)] = newValue
}
get {
return self[distance(string.startIndex, index)]
}
}
}
let str = "1234567890"
let arr = Array<Double>(count: countElements(str), repeatedValue: 0.0)
for var i = str.startIndex; i < str.endIndex; i = i.successor() {
println(arr[str, i])
}
It would be nice if it were possible to use only String.Index when indexing an element. Unfortunately it is not possible to subclass Array as it is defined as a struct. So if we want to use a single parameter index we need to define a wrapper and pass-through the relevant calls. Like this:
Update 2015.02.19: The above implementation of StringIndexArray will fail if the string it is created from is updated later. See my next blog about "That pesky String.Index, part 2"
Update 2015.05.07: When the presented Array extension is used, be aware that the String.endIndex may "count" too many characters when "Combining" characters (unicode \u + CC + xx) are present in the base string.
Happy coding...
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.
class StringIndexArray<T> {
var array: Array<T> = []
var startIndex: String.Index
init(forString: String) {
self.startIndex = forString.startIndex
}
subscript (index: String.Index) -> T {
set {
array[distance(startIndex, index)] = newValue
}
get {
return array[distance(startIndex, index)]
}
}
// pass through of relevant calls
func append(value: T) { array.append(value) }
}
Update 2015.05.07: When the presented Array extension is used, be aware that the String.endIndex may "count" too many characters when "Combining" characters (unicode \u + CC + xx) are present in the base string.
Happy coding...
Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH
We don't get the world we wish for... we get the world we pay for.
No comments:
Post a Comment