将数字转换为特定范围内的等价物
Posted
技术标签:
【中文标题】将数字转换为特定范围内的等价物【英文标题】:Converting a number to its equivalent in a specific range 【发布时间】:2015-09-22 21:06:32 【问题描述】:我在做某事时遇到了困难,我想将一个数字转换为给定范围内的“等效”。 虽然这个概念很简单,但很难解释,所以我会尽力而为。
假设你有一个无限行的瓷砖,但虽然有无限数量的瓷砖,但重复的是完全相同的颜色图案,就像这样:
如您所见,我为每个图块指定了一个数字,但我们可以取一个范围,从 0 到 4,然后说: 0 为紫色 1 是蓝色 2是红色 3是绿色 4是黄色的
但是由于这种颜色模式是无限重复的,实际上,5 与 0 的颜色相同,6 与 1 的颜色相同,8 与 3 的颜色相同。 此外,我们不能忘记负数,例如 -1 将与 4 具有相同的颜色。
实际上,我想要做的是将任何给定的数字转换为我选择的范围的数字,这里是范围 [0;4],这样我就可以知道这个特定图块对应的颜色。 我也希望这种方法适用于其他范围,例如,如果我的范围是 [1;5] 甚至 [-7;-3],它也应该有效。
我已经找到了一种适用于[0;n]
范围(n
为正整数)和a
为另一个正整数的方法:
convertedNumber = a % (n+1)
这是它提供的游乐场:
但它仅适用于我描述的条件,经过数小时的努力,我仍然找不到任何好的解决方案来使其适用于任何数字,无论是正数还是负数,以及任何范围。
不要犹豫,在 cmets 中询问更多详细信息。
谢谢。
【问题讨论】:
范围是什么意思?如果您给定的范围是 [1,5] ...这里 1 仍然代表蓝色(因为它是第一种颜色)或红色(因为它是 1 的原始数字)? 也许将 max 和 min 之间的差异添加到 number 中,max 和 min 可以解决问题? @karthik 当我说一个范围时,比如 [a,b],我的意思是包含在 a 和 b 中的所有整数,包括 a 和 b。所以对于 [1,5] 我们将有 1、2、3、4 和 5。 en.wikipedia.org/wiki/Modulo_operation 那么对于-9
,你想返回1
?
【参考方案1】:
给你。该函数获取您要映射的数字,以及范围的低值和高值,并返回该范围内的值:
func mapNum(n: Int, low lo: Int, high hi: Int) -> Int
let spread = hi - lo + 1
return ((n - lo) % spread + spread) % spread + lo
例子:
mapNum(-9, low: 0, high: 4) // returns "1"
mapNum(-9, low: -3, high: 1) // returns "1"
mapNum(1, low: -11, high: -7) // returns "-9"
mapNum(3, low: -8, high: -4) // returns "-7"
mapNum(-5, low: 4, high: 8) // returns "5"
mapNum(-5, low: -6, high: -2) // returns "-5"
mapNum(-9, low: -7, high: -3) // returns "-4"
【讨论】:
((n - lo) % spread + spread) % spread + lo
与((n - lo) % spread) + lo
相同。解决方案是正确的!
@HW,额外的+ spread % spread
用于解释负数。在 Swift 中,与 C 不同,-7 % 2
是 -1
,我们在这里需要正余数,因此需要额外的“舞蹈”。我不使用条件,因为计算通常比分支更快。
@vacawama 哇!您的功能以一种非常简单的方式完全符合我的要求,非常感谢。我会花时间了解操作!
哦,忽略我的评论然后@vacawama - 我假设 swift 使用“通常的”模运算。
@TrevörAnneDenise,该函数通过使用模运算符 %
计算我们在范围内的距离,然后将其添加到范围的下限以获得最终答案。有关额外的+ spread % spread
的解释,请参阅我上面对@HW 的评论。【参考方案2】:
func modFromRange(range: Range<Int>, ind: Int) -> Int
let endIndex = abs(range.endIndex.predecessor() - range.startIndex).successor()
let i = (ind - range.startIndex) % endIndex
return i < 0 ? (range.startIndex + i + endIndex) : (range.startIndex + i)
modFromRange(1...5, ind: 1) // 1
modFromRange(-7...(-3), ind: -8) // -3
效果如下:
modFromRange(-7...(-3), ind: -7) // -7
modFromRange(-7...(-3), ind: -2) // -7
modFromRange(-7...(-3), ind: -8) // -3
modFromRange(-7...(-3), ind: 1) // -4
modFromRange(1...5, ind: 1) // 1
modFromRange(1...5, ind: 5) // 5
modFromRange(1...5, ind: 6) // 1
modFromRange(1...5, ind: 0) // 5
modFromRange(1...5, ind: -1) // 4
modFromRange(1...5, ind: -9) // 1
For -7...-3:
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]
[ -5, -4, -3, -7, -6, -5, -4, -3, -7, -6, -5, -4, -3, -7, -6, -5, -4, -3]
For 1...5:
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[ 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
或者,在 Swift 2 上,您可以将其作为方法:
extension Range where T : IntegerLiteralConvertible, T : IntegerArithmeticType
func mod(ind: T) -> T
let _endIndex = $0 >= 0 ? $0 : $0 * -1(endIndex - startIndex)
let i = (ind - startIndex) % _endIndex
return i < 0 ? (startIndex + i + _endIndex) : (startIndex + i)
这样的工作方式:
(1...5).mod(1) // 1
(1...5).mod(6) // 1
【讨论】:
您的回答肯定让我想知道为什么我们不能在 SE 上接受多个答案。喜欢你在 Swift 2 中的例子,我会留到以后,它使编写我想要的东西变得非常容易,并且可以按预期工作!非常感谢!【参考方案3】:extension Int
var convertedNumber: Int
if self < 0
return self * -4 % 5 + 1
return ( self % 5 ) + 1
let n = -9
let result = n.convertedNumber // 2
println(result) // 2
(-9).convertedNumber // 2
(-8).convertedNumber // 3
(-7).convertedNumber // 4
(-6).convertedNumber // 5
(-5).convertedNumber // 1
(-4).convertedNumber // 2
(-3).convertedNumber // 3
(-2).convertedNumber // 4
(-1).convertedNumber // 5
(0).convertedNumber // 1
(1).convertedNumber // 2
(2).convertedNumber // 3
(3).convertedNumber // 4
(4).convertedNumber // 5
(5).convertedNumber // 1
(6).convertedNumber // 2
(7).convertedNumber // 3
(8).convertedNumber // 4
(9).convertedNumber // 5
(10).convertedNumber // 1
【讨论】:
扩展提供了一种有趣且现代的方式来编写代码。您的代码几乎符合我的要求,因为实际上,在我的示例中,-1 应该是 5,而不是 4。但感谢您的示例。 @TrevörAnneDenise 您只需在结果中加 1。以上是关于将数字转换为特定范围内的等价物的主要内容,如果未能解决你的问题,请参考以下文章