How to offset a Range<T> in Swift? - swift

Imagine we have an arbitrary Range<T> and we want to create a new range with startIndex and endIndex advanced by 50 units.
My first thought was to do this:
let startIndex = advance(range.startIndex, 50)
let endIndex = advance(range.endIndex, 50)
var newRange = startIndex..<endIndex
But this gives "fatal error: can not increment endIndex". (Well, it does with Range<String.Index>. I haven't tried it with other generic parameters.) I've tried quite a few permutations of this, including assigning range.startIndex and range.endIndex to new variables, etc. Nothing works.
Let me stress that I'm looking for a solution that works with any T. GoZoner gave an answer below that I haven't tried with Int, but I wouldn't be surprised if it worked. However, no permutation of it I tried will work when T is String.Index
So, how can I do this?

There’s a second version of advance that takes a maximum index not to go beyond:
let s = "Hello, I must be going."
let range = s.startIndex..<s.endIndex
let startIndex = advance(range.startIndex, 50, s.endIndex)
let endIndex = advance(range.endIndex, 50, s.endIndex)
var newRange = startIndex..<endIndex
if newRange.isEmpty {
println("new range out of bounds")
}

Try:
1> var r1 = 1..<50
r1: Range<Int> = 1..<50
2> var r2 = (r1.startIndex+50)..<(r1.endIndex+50)
r2: Range<Int> = 51..<100

Related

return "location" of variable in a string

This is a bit on an odd ball question and I am not sure if it is possible to do, none the less.
I am trying to identify the "count" position of an item within a string.
For instance if I have a string: "hello what a lovely day" (23 characters) and I would like to know where in the sting the spaces are. In this case the sting would have a space at the 6th, 11th, 13th and 20th characters. Is there a function that would provide this feedback?
Any insight would be appreciated.
Thank you in advance for your valued time and insight.
Try this extension:
extension String {
func indicesOf(string: String) -> [Int] {
var indices = [Int]()
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.range(of: string, range: searchStartIndex..<self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
}
Usage (note that in Swift, nth characters start at 0 and not 1):
let string = "hello what a lovely day"
let indices = string.indicesOf(string: " ")
print("Indices are \(indices)")
Indices are [5, 10, 12, 19]

Split a large [MLMultiArray] into smaller chunks [[MLMultiArray]]?

I have a large MLMultiArray of length 15360 values.
Sample:
Float32 1 x 15360
[14.78125,-0.6308594,5.609375,13.57812,-1.871094,-19.65625,9.5625,8.640625,-2.728516,3.654297,-3.189453,-1.740234...]
Is there a way I can convert this huge array into 120 small MLMultiArrays with 128 elements each without changing the sequence of this array and in the most efficient way possible?
The entire array of 15360 elements is available in this Link
let chunkSize = 2
let shape = yourLargeArray.shape
let chunkedArrays = try? stride(from: 0, to: shape.count, by: chunkSize)
.map { offset -> MLMultiArray in
let startIndex = shape.index(shape.startIndex, offsetBy: offset)
let endIndex = shape.index(startIndex, offsetBy: chunkSize, limitedBy: shape.endIndex) ?? shape.endIndex
return try MLMultiArray(
shape: Array(shape[startIndex ..< endIndex]),
dataType: yourLargeArray.dataType
)
}

Swift Remainder operator precision

I need to round stocks, indices and futures prices to the nearest tick. The first step is to look if the price is a multiple of the tick. Apple docs says "Unlike the remainder operator in C and Objective-C, Swift’s remainder operator can also operate on floating-point numbers".
If I write the following code in a playground or in a console app and I run it, I expect 0 as result but I get a remainder value equals to 0.00999999999999775:
var stringPrice = "17.66"
var price = Double(stringPrice)
var tickSize: Double = 0.01
let remainder = price! % ticksize
This problem breaks my rounding function when using values such 17.66 as aPrice and 0.01 as aTickSize:
func roundPriceToNearestTick(Price aPrice: Double, TickSize a TickSize: Double)-> Double{
let remainder = aPrice % aTickSize
let shouldRoundUp = remainder >= aTickSize/2 ? true : false
let multiple = floor(aPrice/aTickSize)
let returnPrice = !shouldRoundUp ? aTickSize*multiple : aTickSize*multiple + aTickSize
return returnPrice
}
What is the best way to fix this?
Following the comments about the broken floating point math and the need to avoid floats and doubles for all the operations concerning money I changed my code to perform the remainder operation using NSDecimalNumbers. This seems to solve the precision problem.
var stringPrice = "17.66"
var tickSizeDouble : Double = 0.01
var tickSizeDecimalNumber: NSDecimalNumber = 0.01
func decimalNumberRemainder(Dividend aDividend: NSDecimalNumber, Divisor aDivisor: NSDecimalNumber)->NSDecimalNumber{
let behaviour = NSDecimalNumberHandler(roundingMode: NSRoundingMode.RoundDown,
scale: 0,
raiseOnExactness: false ,
raiseOnOverflow: false,
raiseOnUnderflow: false,
raiseOnDivideByZero: false )
let quotient = aDividend.decimalNumberByDividingBy(aDivisor, withBehavior: behaviour)
let subtractAmount = quotient.decimalNumberByMultiplyingBy(aDivisor)
let remainder = aDividend.decimalNumberBySubtracting(subtractAmount)
return remainder
}
let doubleRemainder = Double(stringPrice)! % tickSizeDouble
let decimalRemainder = decimalNumberRemainder(Dividend: NSDecimalNumber(string: stringPrice), Divisor:tickSizeDecimalNumber)
print("Using Double: \(doubleRemainder)")
print("Using NSDecimalNumber: \(decimalRemainder)")

Swift Range Type endIndex

If you create a var Range = 0...0, I would expect the endIndex to be zero. But in reality is 1.
var myRange: Range<Int> = 0...0
print("start Index \(myRange.startIndex) End Index \(myRange.endIndex)")
output: "start Index 0 End Index 1"
How can I question a Range instance if an Index of type Int is contained ?
The endIndex is not actually included in the Range. The Range is startIndex ..< endIndex. So, for your example, 0...0 is stored as 0..<1 which means the same thing.
For Swift 1.2 you can use the global function contains to check if an Int is contained by a Range:
var myRange: Range<Int> = 0...0
let i: Int = 1
if contains(myRange, i) {
println("yes")
} else {
println("no") // prints "no"
}
For Swift 2.0:
var myRange: Range<Int> = 0...0
let i: Int = 1
if myRange.contains(i) {
print("yes")
} else {
print("no") // prints "no"
}
Maybe you could refer to Half-Open Range Operator
var myRange: Range<Int> = 0..<0
outputs:"start Index 0 End Index 0"
The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. And the closed range operator (a...b) will finally turn to (a..<b+1)
Because Range is also a collection, you can use its minElement() and maxElement() methods, which will return the correct index, respecting the range being closed (...) or half-open (..<).
So the below code will output zeros as expected:
let range: Range<Int> = 0...0
let min = range.minElement()!
let max = range.maxElement()!
print("min=\(min), max=\(max)")
// Output: "min=0, max=0"
Note: both methods have O(elements.count) complexity which might not be suitable for some cases.

Split a double by dot to two numbers

So I am trying to split a number in swift, I have tried searching for this on the internet but have had no success. So first I will start with a number like:
var number = 34.55
And from this number, I want to create two separate number by splitting from the dot. So the output should be something like:
var firstHalf = 34
var secondHalf = 55
Or the output can also be in an array of thats easier. How can I achieve this?
The easiest way would be to first cast the double to a string:
var d = 34.55
var b = "\(d)" // or String(d)
then split the string with the global split function:
var c = split(b) { $0 == "." } // [34, 55]
You can also bake this functionality into a double:
extension Double {
func splitAtDecimal() -> [Int] {
return (split("\(self)") { $0 == "." }).map({
return String($0).toInt()!
})
}
}
This would allow you to do the following:
var number = 34.55
print(number.splitAtDecimal()) // [34, 55]
Well, what you have there is a float, not a string. You can't really "split" it, and remember that a float is not strictly limited to 2 digits after the separator.
One solution is :
var firstHalf = Int(number)
var secondHalf = Int((number - firstHalf) * 100)
It's nasty but it'll do the right thing for your example (it will, however, fail when dealing with numbers that have more than two decimals of precision)
Alternatively, you could convert it into a string and then split that.
var stringified = NSString(format: "%.2f", number)
var parts = stringifed.componentsSeparatedByString(".")
Note that I'm explicitly calling the formatter here, to avoid unwanted behavior of standard float to string conversions.
Add the following extension:
extension Double {
func splitIntoParts(decimalPlaces: Int, round: Bool) -> (leftPart: Int, rightPart: Int) {
var number = self
if round {
//round to specified number of decimal places:
let divisor = pow(10.0, Double(decimalPlaces))
number = Darwin.round(self * divisor) / divisor
}
//convert to string and split on decimal point:
let parts = String(number).components(separatedBy: ".")
//extract left and right parts:
let leftPart = Int(parts[0]) ?? 0
let rightPart = Int(parts[1]) ?? 0
return(leftPart, rightPart)
}
Usage - Unrounded:
let number:Double = 95.99999999
let parts = number.splitIntoParts(decimalPlaces: 3, round: false)
print("LeftPart: \(parts.leftPart) RightPart: \(parts.rightPart)")
Outputs:
LeftPart: 95 RightPart: 999
Usage Rounded:
let number:Double = 95.199999999
let parts = number.splitIntoParts(decimalPlaces: 1, round: true)
Outputs:
LeftPart: 95 RightPart: 2
Actually, it's not possible to split a double by dot into two INTEGER numbers. All earlier offered solutions will produce a bug in nearly 10% of cases.
Here's why:
The breaking case will be numbers with decimal parts starting with one or more zeroes, for example: 1.05, 11.00698, etc.
Any decimal part that starts with one or more zeroes will have those zeroes discarded when converted to integers. The result of those conversions:
1.05 will become (1, 5)
11.00698 will become (11, 698)
An ugly and hard to find bug is guaranteed...
The only way to meaningfully split a decimal number is to convert it to (Int, Double). Below is a simple extension to Double that does that:
extension Double {
func splitAtDecimal() -> (Int, Double) {
let whole = Int(self)
let decimal = self - Darwin.floor(self)
return (whole, decimal)
}
}