将UnitLength的Measurement()数组转换为相同的自然比例

时间:2018-11-02 10:56:34

标签: ios swift foundation

我有一个要在图表中可视化的UnitLength值(爬升高度)数组。 原始数据以米为单位存储,因此我需要将这些值转换为用户的本地化单位(例如英尺)。 苹果为此提供了出色的API:

let measurementFormatter = MeasurementFormatter()
measurementFormatter.unitOptions = .naturalScale
let measurement = Measurement(value: valueInMeters, unit: UnitLength.meters)
measurementFormatter.string(from: measurement)

所以现在,我将一个数据点转换为自然比例。但是,我现在需要将整个Dayapoints数组转换为SAME单位。但是我不知道measurementFormatter使用了哪个单位。产生的单位是多少?

否则,如果我分别转换所有值,则某些值会非常小,因此naturalScale将为英寸。 最后,我希望naturalScale依赖于平均值或中位数,以便大多数值都在其自然比例中。

除了弄像这样的愚蠢的事情之外,我无法弄清楚使用此API怎么可能:

let symbol = measurementFormatter.string(from: measurement).split(separator: " ").last?.lowercased()
// is there not better way to get the UnitLength from naturalScale conversion result?

if symbol == "m" {
    return .meters
}
if symbol == "ft" {
    return .feet
}
if symbol == "yd" {
    return .yards
}
if symbol == "in" {
    return .inches
}
if symbol == "cm" {
    return .centimeters
}
if symbol == "mm" {
    return .millimeters
}
if symbol == "km" {
    return .kilometers
}
if symbol == "mi" {
    return .miles
}

但是我不想发送此代码。没有更好的选择了吗?

1 个答案:

答案 0 :(得分:1)

让我们从这个数组开始:

let dataPoints = [0.0001, 0.1, 1, 2, 3, 1000, 2000]

最适合此数组的单位是中位数:

let median = dataPoints.sorted(by: <)[dataPoints.count / 2]
let medianMeasurement = Measurement(value: 1700, unit: UnitLength.meters)

在下面的代码段中,我们找出最合适的单位,如果单位小于数据点,则将其视为自然单位:

let imperialUnitsNames: [UnitLength] = [.inches,
                                        .feet,
                                        .yards,
                                        .fathoms,
                                        .furlongs,
                                        .miles,
]

let imperialUnitsInMeters: [Any] = imperialUnitsNames.map { unit in
    let m = Measurement(value: 1, unit: unit).converted(to: .meters)
    return m.value
}

let zipped = zip(imperialUnitsInMeters, imperialUnitsNames)
let naturalUnit = zipped.reversed()
    .first(where: { $0.0 < median})!
    .1

您可以在imperialUnitsNames中自定义可能的单位。

让我们创建一个度量格式器:

let measurementFormatter = MeasurementFormatter()
measurementFormatter.unitOptions = .providedUnit

现在我们准备格式化dataPoints

let measurementStrings: [String] = dataPoints.map { dataPoint in
    let measurement = Measurement(value: dataPoint, unit: UnitLength.meters)
    let newMeasurement = measurement.converted(to: naturalUnit)
    return measurementFormatter.string(from: newMeasurement)
}

print(measurementStrings) //["0 ftm", "0.055 ftm", "0.547 ftm", "1.094 ftm", "1.64 ftm", "546.807 ftm", "1,093.613 ftm"]