arithmetic within string literal in Swift - ios

Playing with Swift, I found something awkward error.
let cost = 82.5
let tip = 18.0
let str = "Your total cost will be \(cost + tip)"
This works fine as I expect, but
let cost = 82.5
let tip:Float = 18
let str = "Your total cost will be \(cost + tip)"
would not work with error
could not find member 'convertFromStringInterpolationSegment'
let str = "Your total cost will be \(cost + tip)"
The difference between two example is declaring tip constant to explicitly float or not. Would this be reasonable result?

You still need to cast the numbers into the same type so they can be added together, e.g:
let cost = 82.5
let tip:Float = 18
let str = "Your total cost will be \(Float(cost) + tip)"
By default real number literals are inferred as Double, i.e:
let cost:Double = 82.5
So they need to be either explicitly cast to a Double or a Float to be added together.

Values are never implicitly converted to another type.
let cost = 82.5
let tip:Float = 18
let str = "Your total cost will be \(cost + tip)"
In the above example it is considering cost as double & you have defined tip as float, so it is giving error.
Rather specify the type of cost as float as shown below
let cost:Float = 82.5
Hope it will solve your problem.

In your code cost in inferred to be of type Double.
In your first (working) example tip is also inferred to be Double and the expressions cost + tip is an addition of two Double values, resulting in a Double value.
In your second (not working) example tip is declared to be Float therefore the expressions cost + tip is an error.
The error message is not very informative. But the problem is that you are adding a Double to a Float and in a strongly statically typed language you will not have automatic type conversions like you had in C or Objective C.
You have to do either Float(cost) + tip or cost + Double(tip)

Related

How to get substring from user input?

i wrote code to get character when user enter in text field and do math with them
this :
#IBOutlet weak internal var textMeli: UITextField!
var myChar = textMeli.text
var numb = [myChar[0]*3 , myChar[1]*7]
but one is wrong
textMeli.text is a String.
myChar is a String.
You can't access a Character from a String using bracket notation.
Take a look at the documentation for the String structure.
You'll see that you can access the string's characters through the characters property. This will return a collection of Characters. Initalize a new array with the collection and you can then use bracket notation.
let string = "Foo"
let character = Array(string.characters)[0]
character will be of type Character.
You'll then need to convert the Character to some sort of number type (Float, Int, Double, etc.) to use multiplication.
Type is important in programming. Make sure you are keeping track so you know what function and properties you can use.
Off the soap box. It looks like your trying to take a string and convert it into a number. I would skip the steps of using characters. Have two text fields, one to accept the first number (as a String) and the other to accept the second number (as a String). Use a number formatter to convert your string to a number. A number formatter will return you an NSNumber. Checking out the documentation and you'll see that you can "convert" the NSNumber to any number type you want. Then you can use multiplication.
Something like this:
let firstNumberTextField: UITextField!
let secondNumberTextField: UITextField!
let numberFormatter = NumberFormatter()
let firstNumber = numberFormatter.number(from: firstNumberTextField.text!)
let secondNumber = numberFormatter.number(from: secondNumberTextField.text!)
let firstInt = firstNumber.integerValue //or whatever type of number you need
let secondInt = secondNumber.integerValue
let product = firstInt * secondInt
Dealing with Swift strings is kind of tricky because of the way they deal with Unicode and "grapheme clusters". You can't index into String objects using array syntax like that.
Swift also doesn't treat characters as interchangeable with 8 bit ints like C does, so you can't do math on characters like you're trying to do. You have to take a String and cast it to an Int type.
You could create an extension to the String class that WOULD let you use integer subscripts of strings:
extension String {
subscript (index: Int) -> String {
let first = self.startIndex
let startIndex = self.index(first, offsetBy: index)
let nextIndex = self.index(first, offsetBy: index + 1)
return self[startIndex ..< nextIndex]
}
}
And then:
let inputString = textMeli.text
let firstVal = Int(inputString[0])
let secondVal = Int(inputString[2])
and
let result = firstVal * 3 + secondVal * 7
Note that the subscript extension above is inefficient and would be a bad way to do any sort of "heavy lifting" string parsing. Each use of square bracket indexing has as bad as O(n) performance, meaning that traversing an entire string would give nearly O(n^2) performance, which is very bad.
The code above also lacks range checking or error handling. It will crash if you pass it a subscript out of range.
Note that its very strange to take multiple characters as input, then do math on the individual characters as if they are separate values. This seems like really bad user interface.
Why don't you step back from the details and tell us what you are trying to do at a higher level?

index rows by year in F#

i am reading my data as a frame on F# as follows
let myannual = Frame.ReadCsv("data/annual.csv")
My frame consists of time series columns and a year column, and I would like to index my time series by year. I cannot do it as follows
let myyears = [| for i in myannual.GetColumn<float>("yyyy").Values -> float i |]
let myindexedframe = myannual.IndexRows(myyears)
What should I do? Any feedback is appreciated!
The ReadCsv method takes an optional parameter indexCol that can be used to specify the index column - and you also need to provide a type parameter to tell Deedle what is the type of the index:
let myannual = Frame.ReadCsv<int>("data/annual.csv", indexCol="yyy")
Your approach would work too, but you'd need to use IndexRowsWith, which takes a sequence of new indices (and it is better to use int because float is imprecise for years):
let myyears = [| for i in myannual.GetColumn<float>("yyyy").Values -> int i |]
let myindexedframe = myannual.IndexRowsWith(myyears)
The IndexRows method takes just the name of a column (very similar to using the indexCol parameter when calling ReadCsv):
let myindexedframe = myannual.IndexRows<int>("yyyy")

Could not find an overload for '/' in Swift [duplicate]

I have converted a String to an Int by by using toInt(). I then tried multiplying it by 0.01, but I get an error that says Could not find an overload for '*' that accepts the supplied argument. Here is my code:
var str: Int = 0
var pennyCount = 0.00
str = pennyTextField.text.toInt()!
pennyCount = str * 0.01
From reading other posts it seems that the answer has to do with the type. For example if the type is set as an Integer then it gets a similar error. I have tried changing the type to an Int, but that doesn't seem to solve the problem.
I have also tried setting the type for 'str' and 'pennyCount' as Floats and Doubles and all combinations of Floats, Doubles, and Ints. My guess is the the problem has to do with toInt() function's conversion of a String to an Integer.
Could someone help clarify what the issue may be?
Swift seems to be fairly picky about implied type casting, so in your example you're multiplying str (an Integer) by 0.01 (a Double) so to resolve the error, you'll need to cast it like this:
var str: Int = 0
var pennyCount = 0.00
str = pennyTextField.text.toInt()!
pennyCount = Double(str) * 0.01

Swift: Errors when using different integer sizes

I've been trying out Swift, since it's obviously the direction that Apple wants us to go in.
However, I've been really annoyed with the fact that you can't seem to add integers of different sizes:
var a: Int64 = 1500
var b: Int32 = 12349
var c = a + b
if a < b { ... }
The yielded error is "Could not find an overload for '+' that accepts the supplied argument' — obviously since they are object types. None of the class methods seem to be of any help in up/down-converting integers.
Same situation applies with any of the type aliases, obviously, (CInt + CLong).
I can see a lot of real-world situations where it is immensely practical to be able to do integer arithmetic let alone comparisons or bitwise operations on two disparately-sized integers.
How to solve this? Explicit casting with the as operator doesn't seem to work. The Swift language book isn't much help either as it doesn't really discuss this scenario.
The Swift language book does discuss this scenario in the chapter “Numeric Type Conversion”:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values.
let a: Int64 = 1500
let b: Int32 = 12349
let c = a + Int64(b)
println("The value of c is \(c)")

Converting from m/s to km/h using F# Units of Measure

I'm in the process of learning F# - and is currently looking into Units of Measure. I have a simple calculation returning meters per second, and I want to introduce a function converting it to kilometres per hour.
My code looks like this:
[<Measure>] type kg
[<Measure>] type s
[<Measure>] type m
[<Measure>] type km
[<Measure>] type h
let msToKmph(speed : float<m/s>) =
(float speed) * 3.6<km/h>
let gravityOnEarth = 9.81<m/s^2>
let heightOfJump = 3.5<m>
let speedOfImpact = sqrt (2.0 * gravityOnEarth * heightOfJump)
let speedOfImpactKmh = msToKmph(speedOfImpact)
This works - I get 8.28673639 m/s and 29.832251 km/h. What I am unsure of is if this is the best way to express the relationship between different units. Can this be done more elegantly?
For instance, the line doing (float speed) to remove the unit information from the speed parameter, to make the msToKmph return km/h. If I did not remove unit information before doing the calculation, the returned unit would be: km m/(h s)
First, your msToKmph is totally incorrect. Although it returns a correct return value, what it is actually doing, is it just drops the original <m/s> value by converting to a plain, measureless float and then multiplies the measureless value to a 3.6<km/h>.
To better express the relations between UoM's, consider this:
let kmToM = 1000.0<m/km> // relation between kilometers and meters
let hrToSec = 3600.0<s/h> // relation between seconds and hours
let msToKmph(speed : float<m/s>) =
speed / kmToM * hrToSec
Note, all "magic numbers" are encapsulated within UoM converters, hence your formulas remain clean, e.g. they simply operate values and constants, but the UoM are calculated by the compiler.
Update: The philosophy of UoM conversion is that the conversion formulas should be something that has physical sense. The rule of thumb is whether your conversion value presents in reference books. In plain English, 3.6<km/h> from above is useless, but 1000.0<m/km> just says, "there is 1000 m in 1 km", which makes sense.
You can even improve hrToSec like this:
let hrToSec2 = 60.0<s/minute> * 60.0<minute/h>
This will make every value a well-known value found in reference books.
You're right that removing unit information is a bad thing. You should create a few constants with appropriate units for conversion.
let mPerKm = 1000.0<m/km>
let secondPerHour = 3600.0<s/h>
// val msToKmph : float<m/s> -> float<km/h>
let msToKmph(speed : float<m/s>) =
speed / mPerKm * secondPerHour
For km and m, a generic solution is to define a unit prefix k so it works for many UoMs which have kilo as a metric:
[<Measure>] type k
let kilo = 1000.0<1/k>
let secondPerHour = 3600.0<s/h>
// val msToKmph : float<m/s> -> float<k m/h>
let msToKmph(speed : float<m/s>) =
speed / kilo * secondPerHour

Resources