2017-03-15 109 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

是的,意識到這可能是在寫完上述所有內容之後出現的。 :( –

相關問題