Reputation: 39
I'm making a unit convertor, I'm using an array like this :
private var subContentArray = [["Millimeter", "Centimeter", "Meter", "Kilometer", "Foot", "Yard", "Mile"],
["Milliliter", "Centiliter", "Liter", "Gallon", "Quart", "Pint", "Fluid ounce"],
["Milligram", "Centigram", "Gram", "Kilogram", "Stone", "Pound", "Ounce"]]
And I'm using a picker that is set with 3 piker fields :
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView.tag == 0 {
currentSelection = row
self.pickerGeneral.text = self.pickerGeneral1[row]
self.view.endEditing(true)
} else if pickerView.tag == 1 {
self.pickerTextField.text = self.pickerSubContent[currentSelection][row]
self.view.endEditing(true)
} else if pickerView.tag == 2 {
self.pickedTextField2.text = self.pickerSubContent[currentSelection][row]
self.view.endEditing(true)
}
}
I wanna change the 2nd and 3rd picker by the General picker. So far everything is good, but then I wanna make the calculations and I was trying to do something like this :
func updateOutput(){
//var res: Double
var result: Double
if input.text!.isEmpty {
return
} else if pickerTextField.text! == "Centimeter" && pickedTextField2.text == "Mile" {
result = (Double(self.input.text!)! / 160934.4)
self.output.text! = String("\(result)")
} else if pickerTextField.text! == "Mile" && pickedTextField2.text! == "Centimeter" {
result = (Double(self.input.text!)! * 160934.4)
self.output.text! = String("\(result)")
} else if pickerTextField.text! == "Centimeter" && pickedTextField2.text == "Millimeter" {
result = (Double(self.input.text!)! * 10)
self.output.text! = String("\(result)")
} else if pickerTextField.text! == "Millimeter" && pickedTextField2.text! == "Centimeter" {
result = (Double(self.input.text!)! / 10)
self.output.text! = String("\(result)")
}
...until I realize that if I'm gonna keep writing if/else if...i won't end soon and it will look really messy!
I'm still a noob in to OOP and this branch but willing to learn...so, any help, with example and explains will be very well appreciated!!!!
Upvotes: 0
Views: 64
Reputation: 701
I understand why your array is broken into rows: row 0 is length, row 1 is volume, row 2 is weight/mass.
You could create a corresponding variable with the conversions between each pair:
private var conversions = [[10, 100, 1000, 0.0003048, 3, 1760] .....
Then, once a start and end unit are selected within a row, iterate over conversions
and apply each one until the desired unit is reached. (Be sure to multiply if going in one direction, and divide if going the other way.)
For example, going from Millimeters to Feet, you would perform input / 10 / 100 / 1000 / 0.0003048
. If going from Feet to Millimeters, you would perform input * 0.0003048 * 1000 * 100 * 10
This would be simple enough if your unit list isn't going to change often. Your if-statement could be a for-loop iterating from the start unit index to the end unit index and applying the conversion factor at each step.
Although this isn't very OO, I think it's straightforward for people familiar with unit analysis.
Upvotes: 0
Reputation: 66371
You can use a dictionary:
let factors : [(String, String): Double] = [("Centimeter", "Mile"): 1.0/160934.4,
("Mile", "Centimeter"): 160934.4,
<and more...>]
and your function becomes
func updateOutput(){
if input.text!.isEmpty {
return
}
let result = (Double(self.input.text!)! * factors[(pickerTextField.text, pickerTextField2.text)]
self.output.text! = String("\(result)")
}
(Warning: completely untested.)
Using a common base unit would be even better.
let in_meters: [String: Double] = ["Centimeter": 0.01,
"Meter": 1.0,
"Mile": 1609.344,
<and so on...>]
func updateOutput(){
if input.text!.isEmpty {
return
}
let meters = (Double(self.input.text!)! * in_meters[pickerTextField.text]
let result = meters * 1.0 / in_meters[pickerTextField2.text]
self.output.text! = String("\(result)")
}
Upvotes: 1
Reputation: 63271
First of all, it doesn't make sense for Centimeter
and Mile
to exist within the same array. Arrays aren't an appropriate data structure choice for that, anyway.
I suggest you use a separate enumeration for each type of unit (mass, volume, length, etc.). Enumerations are a way to store a finite set of related values. In this case, you might have a LengthUnit
enumeration:
enum LengthUnit {
case Millimeter
case Cenitmeter
case Meter
case Kilometer
//...
}
Now, rather than defining the explicit relationship between every possible pair of units, you would define (in the enumeration) the conversion factor between each unit and a standard base unit (such as the meter). You would then use this standard base unit as a way to convert from the given unit to the desired unit.
For example, if I wanted to convert 1.5km to miles, I would first convert 1.5km to meters using the conversion from km to meters (1km = 1000 meters), to get 1500. Then I would use the reciprocal of the conversion from miles to meters (1 mile = 1609.34 meters). In all, it would be: 1.5km * (1000m/km) * (1 mile/1609.34m) = 0.93 miles
Upvotes: 1