динамическая математика для охвата значений между несколькими единицами - PullRequest
1 голос
/ 25 марта 2020

Это функция, которую я сейчас использую для преобразования значения одной единицы в другую. Я ищу более динамичный вариант c. Я хочу, чтобы функция была в состоянии преобразовать, например, от 1 килограмма до унции, но почему я делаю это сейчас, я определил, насколько каждая единица сравнивается с другой. Есть ли более простой способ сделать это?

    func weightMath(_ input: UITextField, _ textField: UITextField) {
    //The math for doing weight calculations. This will also round up the answer to the third decimal.
    switch input.tag {
        /*
         case 0 is for when the user want to calculate from kilogram
         case 1 is for when the user want to calculate from ounces
         case 2 is for when the user want to calculate from pounds
         */
    case 0:
        switch textField.tag {
            /*
            case 0 is for when the user want to calculate to kilogram
            case 1 is for when the user want to calculate to ounces
            case 2 is for when the user want to calculate to pounds
            */
        case 0:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 1)
        case 1:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 35.274)
        case 2:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 2.205)
        default:
            break
        }
    case 1:
        switch textField.tag {
            /*
            case 0 is for when the user want to calculate to kilogram
            case 1 is for when the user want to calculate to ounces
            case 2 is for when the user want to calculate to pounds
            */
        case 0:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 0.028)
        case 1:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 1)
        case 2:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 0.063)
        default:
            break
        }
    case 2:
        switch textField.tag {
            /*
            case 0 is for when the user want to calculate to kilogram
            case 1 is for when the user want to calculate to ounces
            case 2 is for when the user want to calculate to pounds
            */
        case 0:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 0.454)
        case 1:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 16)
        case 2:
            textField.text = String(format: "%.3f", toFloat(input.text!) * 1)
        default:
            break
        }
    default:
        break
    }
}

1 Ответ

1 голос
/ 26 марта 2020

Итак, как уже упоминали люди, использование Measurement API упростит ситуацию, но я не думаю, что это реальная проблема с вашим кодом. Кажется, вы знаете, что с увеличением количества единиц, которые вы конвертируете в / из, ваша weightMath функция быстро выходит из-под контроля (если у вас N единиц, она будет расти пропорционально N ^ 2). Хорошо, что, даже будучи новичком, вы смотрите на этот код и думаете: «Конечно, есть лучший способ».

Главное, что вам не хватает, - это вместо того, чтобы переходить непосредственно от входных единиц к выходным единиц вы должны разбить это на два шага. Выберите какой-нибудь внутренний блок (скажем, килограммы), затем переведите входные данные в эти внутренние блоки и переведите из этих внутренних блоков в выходные блоки.

Давайте посмотрим, как это будет выглядеть в коде. Несмотря на то, что ваша функция называется weightMath, на самом деле она немного мешает работе с пользовательским интерфейсом. Давайте решим это, разбив его на две функции: updateUI, который имеет дело с пользовательским интерфейсом, и convert, который выполняет математику.

Здесь код для updateUI:

func updateUI(_ input: UITextField, _ textField: UITextField) {
    guard let inputString = input.text,
          let inputValue = Double(inputString) else {
        // You may want to do more than just return.
        return
    }
    let convertedValue = convert(mass: inputValue, inputUnitIndex: input.tag, outputUnitIndex: textField.tag)
    textField.text = String(format: "%.3f", convertedValue)
}

Теперь convert может сосредоточиться только на математике. Даже без использования Measurement API мы можем реализовать это довольно просто:

private func convert(mass: Double, inputUnitIndex: Int, outputUnitIndex: Int) -> Double {
    let conversionTable = [ 1.0, 0.0283495, 0.453592 ]
    let massKg = mass * conversionTable[inputUnitIndex]
    return massKg / conversionTable[outputUnitIndex]
}

Несколько замечаний здесь. Таблица преобразования содержит факторы, необходимые для перевода килограммов, унций и фунтов в килограммы путем умножения. Этот же набор значений можно использовать для преобразования из килограммов путем деления. Значение massKg - это значение в наших внутренних единицах , которое я выбрал в килограммах.

Но этот код немного уродлив: он имеет волхвов c констант , и если вы хотите поддерживать больше единиц, вам придется искать коэффициенты пересчета. Использование Measurement API сделает это намного лучше. Вот как это выглядело бы.

private func convert(mass: Double, inputUnitIndex: Int, outputUnitIndex: Int) -> Double {
    let unitLookupTable = [ UnitMass.kilograms, UnitMass.ounces, UnitMass.pounds ]
    let massKg = Measurement(value: mass, unit: unitLookupTable[inputUnitIndex])
    return massKg.converted(to: unitLookupTable[outputUnitIndex]).value
}

Есть еще кое-что, что можно сделать, чтобы сделать это намного приятнее: передача целых чисел здесь не велика ... но это другая история. Надеюсь, это поможет.

...