How to divide an entered time by a Float - time

So I'm making an app where you enter a time (1:32.40) and you then divide this time by a number (50). I made everything a Float so far, but that is clearly not right. How can I have the user enter the time like normal and then convert that to a Float that is easily divisible?
My Calculation function currently looks like this
func calculation() -> Bool{
raceDistance = txtRaceDistance.text
practiceDistance = txtPracticeDistance.text
goalTime = txtGoalTime.text
var fGoalTime = (goalTime as NSString).floatValue
var fRaceDistance = (raceDistance as NSString).floatValue
var fPracticeDistance = (practiceDistance as NSString).floatValue
dividedDistance = fRaceDistance / fPracticeDistance
answer = fGoalTime / dividedDistance
var answerFormat : NSString = NSString(format: "%0.2f", answer)
lblAnswer.text = String(answerFormat)
return true
}
fGoalTime is the only problem, because the user will be typing in something like (1:20.40)

I am assuming that you get an error for this line or just not the correct number.
var fGoalTime = (goalTime as NSString).floatValue
you will need to write a helper function timeStringToFloat(String) -> Float
In there you will want to use String.componentsSeparatedByString() maybe something like this:
func timeStringToFloat(timeString: String) -> Float {
let milliseconds = timeString.componentsSeparatedByString(".")[1]
let seconds = timeString.componentsSeparatedByString(.)[0].componentsSepatatedByString(":")[1]
let minutes = timeString.componentsSeparatedByString(":")[0]
//now we have them all as String
//maybe covert to float then add
let time = Float(minutes) * 60 + Float(seconds) + Float("0."+milliseconds)
return time
}

Related

Displaying float to a variable number of decimal places in Swift

Is there a simple way of displaying a float or double to a relevant number of decimal places in Swift.
For example, an iOS app using SI units, which can be altered depending on the property desired, and converted through up to 6 orders of magnitude depending on desired inputs and output. Therefore it needs to display not only 1mg to 1000 micrograms, but also the other way around - i.e 1 microgram = 0.001 mg.
I can easily format a string as follows:
textFieldFoo.text = NSString(format: "%.1f mg", bar) as String
However, if the user were to convert from 1mcg to 0.001mg, this would display as
0.0 mg
Yet, to include up to 6 decimal places to encompass all common possibilities would lead to an unwieldy, ugly looking UI.
Is there a simple way to format a string, in order to include a float/ double where it is displayed to a relevant number of decimal places/ significant figures? I'm sure, given time and enough boilerplate code, that I could pyramid if/ else it to get a result, but that's frankly inelegant.
There's NSMAssFormatter but it doesn't go all the way down to microgram. It was designed to format human-level weight.
You can roll your own by subclassing NSNumberFormatter:
enum MassUnit: Double {
case Microgram = 1e-6
case Milligram = 1e-3
case Gram = 1
case Kilogram = 1e3
static let allUnits: [MassUnit] = [.Microgram, .Milligram, .Gram, .Kilogram]
var unitAbbreviation: String {
get {
switch self {
case .Microgram: return "mcg"
case .Milligram: return "mg"
case .Gram: return "g"
case .Kilogram: return "kg"
}
}
}
}
class MyMassFormatter: NSNumberFormatter {
func bestFitStringForWeightInGrams(weight: Double) -> String {
var selectedString = self.stringFromNumber(weight)!
var selectedUnit = MassUnit.Gram
// Pick the unit that results in the shortest string
for unit in MassUnit.allUnits {
if let str = self.stringFromNumber(weight / unit.rawValue)
where str.characters.count < selectedString.characters.count {
selectedString = str
selectedUnit = unit
}
}
return selectedString + selectedUnit.unitAbbreviation
}
}
Usage:
let formatter = MyMassFormatter()
formatter.format = "0.######"
print(formatter.bestFitStringForWeightInGrams(0.000001)) // 1mcg
print(formatter.bestFitStringForWeightInGrams(0.005)) // 5mg
print(formatter.bestFitStringForWeightInGrams(2500)) // 2.5kg
print(formatter.bestFitStringForWeightInGrams(1234.5)) // 1234.5g
Formatting to Significant Figures using Swift
What you want is the ability to format to a fixed number of significant figures, rather than a fixed number of decimal places. A good swift option to solve this is using class extensions, with a little maths to decide how many decimal places to show based on the magnitude of the number.
The example below extends the Double class to enable formatting to a fixed number of significant figures and uses either float notation or scientific notation depending on the magnitude of the number.
import Foundation
//extension to format a Double to a fixed number of significant figures
extension Double {
func sigFigs(_ numberOfSignificantFigures: Int) -> String {
let mag = log10(abs(self))
let intMag = Int(mag)
if mag >= 0 {
if intMag < numberOfSignificantFigures {
return String(format: "%.\(numberOfSignificantFigures - intMag - 1)f",self)
}
else {
return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
}
}
else {
if -intMag < numberOfSignificantFigures {
return String(format: "%.\(numberOfSignificantFigures)f",self)
}
else {
return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
}
}
}
}
Usage
let num1 = 1234.5678
let num2 = 12.345678
let num3 = 0.0012345678
let num4 = 1234567.8
print(num1.sigFigs(6))
print(num1.sigFigs(2))
print(num2.sigFigs(6))
print(num2.sigFigs(2))
print(num3.sigFigs(6))
print(num3.sigFigs(2))
print(num4.sigFigs(6))
print(num4.sigFigs(2))
Output
1234.57
1.2e+03
12.3457
12
0.001235
1.2e-03
1.23457e+06
1.2e+06
If I understand you correctly you are:
using Swift
working with SI units
trying to display floating points
trying to avoid boilerplate and possibly magic numbers
You should definitely use Apple's Measurement which is :
A numeric quantity labeled with a unit of measure, with support for unit conversion and unit-aware calculations.
and MeasurementFormatter which is :
A formatter that provides localized representations of units and measurements.
MeasurementFormatter uses a NumberFormatter to format the quantity of a measurement.
NumberFormatters's usesSignificantDigits property is set to false by default but :
Set this property to true to format numbers according to the significant digits configuration specified by the minimumSignificantDigits and maximumSignificantDigits properties. By default, the minimum number of significant digits is 1, and the maximum number of significant digits is 6.
Here's an example of what you can do with masses
let micrograms = Measurement(value: 1, unit: UnitMass.micrograms) // 1.0 µg
let nanograms = micrograms.converted(to: .nanograms) // 1000.0000000000001 ng
let picograms = micrograms.converted(to: .picograms) // 1000000.0 pg
let milligrams = micrograms.converted(to: .milligrams) // 0.001 mg
let centigrams = micrograms.converted(to: .centigrams) // 0.0001 cg
let decigrams = micrograms.converted(to: .decigrams) // 1e-05 dg
let grams = micrograms.converted(to: .grams) // 1e-06 g
let kilograms = micrograms.converted(to: .kilograms) // 1e-09 kg
let ounces = micrograms.converted(to: .ounces) // 3.527399072294044e-08 oz
let pounds = micrograms.converted(to: .pounds) // 2.2046244201837776e-09 lb
let stones = micrograms.converted(to: .stones) // 1.574731232746851e-10 st
let formatter = MeasurementFormatter()
formatter.numberFormatter.usesSignificantDigits = true
formatter.unitOptions = .providedUnit
formatter.string(from: nanograms) // "1 000 ng"
formatter.string(from: picograms) // "1 000 000 pg"
formatter.string(from: micrograms) // "1 µg"
formatter.string(from: milligrams) // "0,001 mg"
formatter.string(from: centigrams) // "0,0001 cg"
formatter.string(from: decigrams) // "0,00001 dg"
formatter.string(from: grams) // "0,000001 g"
formatter.string(from: kilograms) // "0,000000001 kg"
formatter.string(from: ounces) // "0,000000035274 oz"
formatter.string(from: pounds) // "0,00000000220462 lb"
formatter.string(from: stones) // "0,000000000157473 st"

xcode: need to convert strings to double and back to string

this is my line of code.
budgetLabel.text = String((budgetLabel.text)!.toInt()! - (budgetItemTextBox.text)!.toInt()!)
the code works, but when I try to input a floating value into the textbox the program crashes. I am assuming the strings need to be converted to a float/double data type. I keep getting errors when i try to do that.
In Swift 2 there are new failable initializers that allow you to do this in more safe way, the Double("") returns an optional in cases like passing in "abc" string the failable initializer will return nil, so then you can use optional-binding to handle it like in the following way:
let s1 = "4.55"
let s2 = "3.15"
if let n1 = Double(s1), let n2 = Double(s2) {
let newString = String( n1 - n2)
print(newString)
}
else {
print("Some string is not a double value")
}
If you're using a version of Swift < 2, then old way was:
var n1 = ("9.99" as NSString).doubleValue // invalid returns 0, not an optional. (not recommended)
// invalid returns an optional value (recommended)
var pi = NSNumberFormatter().numberFromString("3.14")?.doubleValue
Fixed: Added Proper Handling for Optionals
let budgetLabel:UILabel = UILabel()
let budgetItemTextBox:UITextField = UITextField()
budgetLabel.text = ({
var value = ""
if let budgetString = budgetLabel.text, let budgetItemString = budgetItemTextBox.text
{
if let budgetValue = Float(budgetString), let budgetItemValue = Float(budgetItemString)
{
value = String(budgetValue - budgetItemValue)
}
}
return value
})()
You need to be using if let. In swift 2.0 it would look something like this:
if let
budgetString:String = budgetLabel.text,
budgetItemString:String = budgetItemTextBox.text,
budget:Double = Double(budgetString),
budgetItem:Double = Double(budgetItemString) {
budgetLabel.text = String(budget - budgetItem)
} else {
// If a number was not found, what should it do here?
}

Using a number that is smaller then 1

Hei, I am trying my first steps in Swift coding, and I am trying to build a calculator. It should divide things though 0.5 for example, but I am getting a error message because it cant read 0.5 just full digits like 5. How can I enter number that are smaller then 1? I am very thankful for help! here is my code:
#IBAction func findBudget(sender: AnyObject) {
var enteredBudget = enterBudget.text.toInt ()
var myBudget = enteredBudget! / 0.5
resultMy.text = "My Budget: \(myBudget)"
}
You can covert your Int to a Double:
var myBudget = Double(enteredBudget!) / 0.5
You do this by getting the Double value from your string rather than an Int value. An easy way to do this is to initialize an NSString from your text and use its doubleValue property, or you could cast it to be an NSString.
let enteredBudget = NSString(string: textField.text).doubleValue
let myBudget = enteredBudget / 0.5
println(myBudget)

Passing textFielddata with prepareForSegue as a number and not a string

I am having trouble with the whole string int thing.
I have managed to figure out how to convert each string to a number, however it returns as an optional and when I try to do anything with it I get nil.
My goal is to take 4 inputs from the user.
Each input textField is on separate view controllers.
Each view controller is fed data from variables passed from the view controller before it, using segue prepareForSegue.
Now I get to the last view controller and all the data passes fine, the problem is I cannot do any math with the values held in the variables since they are Strings.
Even after doing the conversion with .int() I cannot do math with them.
This is the last view controller classfile code:
class splitTheBillAmountViewController: UIViewController {
// capture passed data from previous View Controller
var numOfGuests = ""
var subTotalAmount = ""
var taxAmount = ""
var tipAmount = ""
#IBOutlet weak var dynamicTotal: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
println("Split The Bill!”)
// output variables data
println(numOfGuests)
println(subTotalAmount)
println(taxAmount)
println(tipAmount)
// store variables to new name
let string1 = numOfGuests
let string2 = subTotalAmount
let string3 = taxAmount
let string4 = tipAmount
// conversions
let guestNumber : Int? = string1.toInt()
let subTotalNumber : Int? = string2.toInt()
let taxAmountNumber : Int? = string3.toInt()
let tipNumber : Int? = string4.toInt()
// visual to see if numbers are converted .int()
println("\(guestNumber)")
println("\(subTotalNumber)")
println("\(taxAmountNumber)")
println("\(tipNumber)")
// store data to variable
let fTotal : Int? = (guestNumber)
// Update label with total
self.dynamicTotal.text = “fTotal"
// Do any additional setup after loading the view.
}
How can I do math with these variables?
I just need to add them up and divide by var numOfGuests
I'm not sure you want to use Ints for all these values, but that aside I ran this code:
var numOfGuests = "2"
var subTotalAmount = "25"
var taxAmount = "3"
var tipAmount = "2"
let string1 = numOfGuests
let string2 = subTotalAmount
let string3 = taxAmount
let string4 = tipAmount
let guestNumber : Int? = string1.toInt()
let subTotalNumber : Int? = string2.toInt()
let taxAmountNumber : Int? = string3.toInt()
let tipNumber : Int? = string4.toInt()
println("\(guestNumber)")
println("\(subTotalNumber)")
println("\(taxAmountNumber)")
println("\(tipNumber)")
it printed:
Optional(2)
Optional(25)
Optional(3)
Optional(2)
I then modified the print statements to:
println("\(guestNumber!)")
println("\(subTotalNumber!)")
println("\(taxAmountNumber!)")
println("\(tipNumber!)")
It printed:
2
25
3
2
In neither case was the output nil. I think you want to look at how your original strings are getting set. Maybe they're never getting reset from "".
BTW, back to the use of Int types for the calculations, I think you really want to use Float type, not Int.
This code:
var subTotalAmount = "25.15"
let string2 = subTotalAmount
var subTotalNumber = (string2 as NSString).floatValue
println("\(subTotalNumber)")
prints:
25.15
EDIT:
I played with copying your code, and I think you know that you have a typo that the compiler should warn you about. Once I fixed the typo, however I was getting a nil. I got this code to work:
var subTotalAmount = "25.15"
let string2 = subTotalAmount
var subTotalNumber = (string2 as NSString).floatValue
println("\(subTotalNumber)")
let text = NSString(format: "%.2f", subTotalNumber)
println(text)
This prints:
25.15
25.15
EDIT2:
Assuming you have all the numbers as floats, the total bill would be:
var fTotal:Float = subTotalNumber + taxAmountNumber + tipNumber
var costPerGuest:Float = fTotal / guestNumber
let fTotalText = NSString(format: "%.2f", fTotal)
let costPerGuestText = NSString(format: "%.2f", costPerGuest)

How can I concatenate strings only if they have passed a logical statement in Swift?

My challenge is twofold:
To pick individual strings from an array of similar strings, but only if a boolean test has been passed first.
"Finally" I need to concatenate any/all of the strings generated into one complete text and the entire code must be in Swift.
Illustration: A back of the envelope code for illustration of logic:
generatedText.text =
case Int1 <= 50 && Int2 == 50
return generatedParagraph1 = pick one string at RANDOM from a an array1 of strings
case Int3 =< 100
return generatedParagraph2 = pick one string at RANDOM from a an array2 of strings
case Int4 == 100
return generatedParagraph3 = pick one string at RANDOM from a an array3 of strings
...etc
default
return "Nothing to report"
and concatenate the individual generatedParagraphs
Attempt: Code picks a random element within stringArray1, 2 and 3.
Example of what the code returns:
---> "Sentence1_c.Sentence2_a.Sentence3_b."
PROBLEM: I need the code to ONLY pick an element if it has first passed a boolean. It means that the final concatenated string (concastString) could be empty, just contain one element, or several depending on how many of the bools were True. Does anyone know how to do this?
import Foundation
var stringArray1 = ["","Sentence1_a.", "Sentence1_b.", "Sentence1_c."]
var stringArray2 = ["","Sentence2_a.", "Sentence2_b.", "Sentence2_c."]
var stringArray3 = ["","Sentence3_a.", "Sentence3_b.", "Sentence3_c."]
let count1 = UInt32(stringArray1.count)-1
let count2 = UInt32(stringArray2.count)-1
let count3 = UInt32(stringArray3.count)-1
var randomNumberOne = Int(arc4random_uniform(count1))+1
var randomNumberTwo = Int(arc4random_uniform(count2))+1
var randomNumberThree = Int(arc4random_uniform(count3))+1
let concatString = stringArray1[randomNumberOne] + stringArray2[randomNumberTwo] + stringArray3[randomNumberThree]
Okay, I didn't pass a Bool, but I show concatenating three random strings from a [String]. I ran this in a playground.
import Foundation
var stringArray = [String]()
for var i = 0; i < 100; i++ {
stringArray.append("text" + "\(i)")
}
func concat (array: [String]) -> String {
let count = UInt32(stringArray.count)
let randomNumberOne = Int(arc4random_uniform(count))
let randomNumberTwo = Int(arc4random_uniform(count))
let randomNumberThree = Int(arc4random_uniform(count))
let concatString = array[randomNumberOne] + array[randomNumberTwo] + array[randomNumberThree]
return concatString
}
let finalString = concat(stringArray)

Resources