在Double数组中建立范围



我希望建立Double值数组中可能存在的各种范围。这最好用一个例子来解释。假设我有以下一组数字:

[1.5, 1.6, 1.7, 1.8, 2.9, 3.0, 3.1, 4.0]

我希望能够以给定的粒度(在本例中为0.1(确定该集合中的范围为:

1.5-1.8, 2.9-3.1, 4.0

有什么想法吗?

粒度为0.01的示例数据集:

[407.46, 407.47, 407.48, 407.49, 407.5, 407.51, 407.52, 407.53, 407.54, 407.55, 407.56, 407.57, 407.58, 407.59, 407.6, 407.61, 407.62, 407.63, 407.64, 407.65, 407.66, 407.67, 407.68, 407.69, 407.7, 407.71, 407.72, 407.73, 407.74, 407.75, 407.76, 407.77, 407.78, 407.79, 407.8, 407.81, 407.82, 407.83, 407.84, 407.85, 407.86, 407.87, 407.88, 407.89, 407.9, 407.91, 440.27, 440.28, 440.29, 440.3, 440.31, 440.32, 440.33, 440.34, 440.35, 440.36, 440.37, 440.38, 440.39, 440.4, 440.41, 440.42, 440.43, 440.44, 440.45, 440.46, 440.47, 440.48, 440.49, 440.5, 440.51, 440.52, 440.53, 440.54, 440.55, 440.56, 440.57, 440.58, 440.59, 440.6, 440.61, 440.62, 440.63, 440.64, 440.65, 440.66, 440.67, 440.68, 440.69, 440.7, 440.71, 440.72, 440.73, 440.74]

一个更长、更简单的实现:

func getRanges(from values: [Double], with granularity: Double) -> [ClosedRange<Double>] {
if values.count == 1 {
return [values[0]...values[0]]
}
var ranges = [ClosedRange<Double>]()
var lowerBound: Double = 0
var upperBound: Double = 0
for (i, value) in values.enumerated() {
if i == 0 {
lowerBound = value
upperBound = value
continue
}

let multiplier: Double = (1 / granularity).rounded()
let multipliedGranularity = granularity * multiplier
if (value * multiplier - (upperBound * multiplier + multipliedGranularity)).isLess(than: multipliedGranularity) {
upperBound = value
} else {
ranges.append(lowerBound...upperBound)
lowerBound = value
upperBound = value
}

if i == values.count - 1 {
ranges.append(lowerBound...upperBound)
}
}

return ranges
}

使用您的样本,结果是:

ClosedRange(407.46...407.91)
ClosedRange(440.27...440.74)

此代码甚至适用于较小的粒度。例如,使用粒度0.0000000001和以下值:

[407.9999999991, 407.9999999992, 407.9999999994, 407.9999999995]

结果:

ClosedRange(407.9999999991...407.9999999992)
ClosedRange(407.9999999994...407.9999999995)

最新更新