2017-03-15 154 views
0

我目前收到的Int可能在0到180,000之间。我需要改变,以适合0 3000之间,我知道在其他语言中,你可以使用类似如何从一个范围内的数字内插​​到另一个范围内的相应值?

Map(min1,max1,min2,max2,input) 

我似乎无法找到像雨燕里面。 这是我现在有,但它总是返回0

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

我想我使用了错误的功能。我从来没有在Swift中做过任何映射。

+0

http://stackoverflow.com/questions/24132399/how-does-one-make-random-number-between-range-for-arc4random - 统一 – Sahil

+0

“在两个数字之间保留一个数字”是什么意思?你想生成一个随机数吗? –

+0

你的问题还不清楚,但'map'上的文档可以在[这里]找到(https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html)。 – Caleb

回答

2

集合上的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) 
+0

dfri的回答和我的回答有很大的区别,因为我的操作顺序有更多的均匀分布,而他不太可能导致溢出,这一切取决于你在寻找什么 –

+1

建议新函数的不同名称,以避免与现有的'map'混淆? –

+0

也许,我只是保持他的名字完整。 –

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)(左结合/*运营商)可能会溢出。

+0

您需要减去数学之前的最小输入范围值,否则只有当输入范围从零开始时才起作用 –

+0

@DavidBerry:你说得对,谢谢! – dfri

0

目前尚不清楚OP是否想要钳制(标题似乎是这样说的),还是想要从一个边界范围内插到另一个边界范围。标题使我想到了一个,但最大/最小值的双重值使我认为他们在插值之后。我回答了前者。 David Berry对后者有很好的回答。

可能想要的是最小/最大功能。 Swift有这些。以“钳”低和高值之间的值,你通常将二者结合起来:

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 
+0

尽管我同意这一点并不十分清楚,但他的“地图”函数需要两个范围,这意味着他实际上想插入。把它与某个地方的“地图”功能结合起来,看起来很可能就是他们真正想要的。 –

+0

是的,意识到这可能是在写完上述所有内容之后出现的。 :( –

相关问题