如何从一个范围内的数字插值到另一个范围内的相应值?

时间:2017-03-15 17:43:09

标签: swift integer range

我目前收到一个可能介于0到180,000之间的Int。我需要将其更改为0到3000之间。我知道在其他语言中你可以使用类似

的东西
Map(min1,max1,min2,max2,input)

我似乎无法在swift中找到类似的东西。 这是我目前拥有的,但它总是返回0.

var newY = [(Int)(input)]
newY = newY.map {_ in 0 * 3000}
print(newY[0])

我认为我使用了错误的功能。我之前从未在Swift中做过任何映射。

4 个答案:

答案 0 :(得分:3)

集合上的map函数将做一些非常不同的事情。它将映射函数应用于集合的每个元素,并根据结果返回新集合。

您正在寻找的是:

func map(minRange:Int, maxRange:Int, minDomain:Int, maxDomain:Int, value:Int) -> Int {
    return minDomain + (maxDomain - minDomain) * (value - minRange) / (maxRange - minRange)
}

print(map(minRange: 0, maxRange: 1800000, minDomain: 0, maxDomain: 3000, value: 200000))

只需要做更多的工作就可以使它在所有整数类型上都是通用的:

func map<T:IntegerArithmetic>(minRange:T, maxRange:T, minDomain:T, maxDomain:T, value:T) -> T {
    return minDomain + (maxDomain - minDomain) * (value - minRange) / (maxRange - minRange)
}

另一个选择是利用Swift Range类型来调用更简洁:

func map<T:IntegerArithmetic>(range:Range<T>, domain:Range<T>, value:T) -> T {
    return domain.lowerBound + (domain.upperBound - domain.lowerBound) * (value - range.lowerBound) / (range.upperBound - range.lowerBound)
}

map(range:0..<3000, domain:0..<180000, value: 1500)

答案 1 :(得分:0)

鉴于您正在寻找将给定范围内的值的相对位置映射到另一个范围,您可以采取以下措施:

// dummy function name
func transform(_ number: Int, fromRange: (Int, Int), toRange: (Int, Int)) -> Int? {
    guard number >= fromRange.0 && number <= fromRange.1,
        toRange.0 <= toRange.1 else { return nil }
    return toRange.0 + (number-fromRange.0)*(toRange.1-toRange.0)/(fromRange.1-fromRange.0)
}

// ex1
let numberA = 3001
let transformedNumberA = transform(numberA, fromRange: (0, 180_000), toRange: (0,3000))
print(transformedNumberA ?? -1) // 50

// ex2
let numberB = 134_000
let transformedNumberB = transform(numberB, fromRange: (0, 180_000), toRange: (0,3000))
print(transformedNumberB ?? -1) // 2233

// ex3
let numberC = 200_000
let transformedNumberC = transform(numberC, fromRange: (0, 180_000), toRange: (0,3000))
print(transformedNumberC ?? -1) // -1 (nil return)

请注意,(number-fromRange.0)*(toRange.1-toRange.0)/*运算符的左关联性)可能会溢出。

答案 2 :(得分:0)

目前尚不清楚OP是否只想钳位(标题似乎是这样)或想要从一个边界范围内插到另一个边界范围。标题让我想到了一个,但双重最大/最小值让我觉得它们是在插值之后。我回答了前者。大卫贝瑞对后者有一个很好的答案。

可能想要的是最小/最大功能。斯威夫特有这些。要将值“钳制”在低值和高值之间,通常将两者结合起来:

var bottom = 13
var top = 42
var tooLow = 7
var clamped = min(top, max(bottom, tooLow)) -> 13
var justRight = 23
clamped = min(top, max(bottom, justRight)) --> 23
var tooHigh = 99
clamped = min(top, max(bottom, tooHigh))  --> 42

这通常是大多数人去的路线,对大多数人来说可能已经足够好了。我个人讨厌一遍又一遍地写作,我厌倦了不得不考虑哪一方可以提供最大值和最小值。而且我不喜欢它使用看起来像自由函数的东西,我是一个面向对象的消息发送类型的人,所以我做了以下:

precedencegroup MinMaxPrecedence {
    associativity: left
    higherThan: NilCoalescingPrecedence, AdditionPrecedence, MultiplicationPrecedence
}

infix operator <> : MinMaxPrecedence

func <><T:Comparable>(a:T, b:T) -> T {
    return a < b ? a : b
}

infix operator >< : MinMaxPrecedence

func ><<T:Comparable>(a:T, b:T) -> T {
    return a < b ? b : a
}

基本上,这定义了两个可以在采用<>的任何类型之间使用的新运算符(><Comparable)。它们对我来说很容易记住,较小的一个想要较小的值,而一个较大的那个则返回更大的值。什么是好的,然后你可以把它们放在更简单的表达式中:

var bottom = 13
var top = 42
var tooLow = 7
var justRight = 23
var tooHigh = 99
bottom >< tooLow <> top --> 13
bottom >< justRight <> top --> 23
bottom >< tooHigh <> top --> 42

答案 3 :(得分:0)

//Map function
func mapy(n:Double, start1:Double, stop1:Double, start2:Double, stop2:Double) -> Double {
    return ((n-start1)/(stop1-start1))*(stop2-start2)+start2;
};