我想这方面的解决方案非常简单,但我已经考虑了一段时间,但却找不到优雅的解决方案。
我有一系列数字,例如1..10 = (1,2,3,4,5,6,7,8,9,10)
,这是循环的,意味着最后一个之后的数字也是第一个(next(10)=1
)。
对于范围内的给定数字i>0
,我想计算下一个m
- 和之前的m
个数字。例如next(5,1)=6
next(10,1)=1
next(10,2)=2
prev(5,2)=3
prev(1,1)=10
prev(1,2)=9
。
对于next
我可以(i+m)%n
n
,其中n=10
是范围的长度(示例中为prev
)。但对于{{1}}我找不到一个优雅的解决方案。
答案 0 :(得分:30)
只需减去1并在之后加1。
在大多数编程语言中,您需要注意何时找到“上一个”值,因为对于负数,模数在这种情况下不能正常工作:它返回一个负数。
这是C / C ++版本:
int next(int i, int m, int n) { return (i + m - 1) % n + 1; }
int prev(int i, int m, int n) { return (i - m + n - 1) % n + 1; }
但是,在Perl模数中总是返回一个正值(至少当第二个操作数是一个正整数时)。基本上它做你想要的。因此,您可以编写以下内容并省略+ $_[2]
:
sub nxt { ($_[0] + $_[1] - 1) % $_[2] + 1; }
sub prv { ($_[0] - $_[1] - 1) % $_[2] + 1; }
答案 1 :(得分:6)
你的next = (i + m) % n
无论如何都不对 - 在某些情况下它会返回零。
请改为尝试:
next(i, m) = ((i - 1) + m) % n + 1
prev(i, m) = ((i - 1) + n - m) % n + 1
实际上,取一个,然后找到正确的值,然后重新添加一个。
对于prev
,请先添加n
以确保您永远不会使用负数的模数
答案 2 :(得分:2)
next(i,m)
和previous(i,-m)
之间有什么区别?没有!。我们走吧(i - 1 + n + m % n) % n + 1
:
$ perl -le 'sub gen {my $n = shift; return sub{ my ($i, $m) = @_; return ($i - 1 + $n + $m % $n) % $n + 1;};} $"=","; for my $n (2..5) { my $f = gen($n); print "$n: @{[map {$f->(1,$_)} -10 .. 10]}"}'
2: 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1
3: 3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2
4: 3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3
5: 1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1
答案 3 :(得分:1)
如果你不介意,首先要说几句话。
实现“上一步”功能的困惑来自于在正面和负面整数域中思考这个问题。从几何学的角度考虑它,如果你想象一个具有10个等间距点的圆,那么解决方案看起来像这样:
正如您正确指定的那样,给定范围[x..z]
,其范围为圆形,您可以找到下一个m-th number
为(i+m)%k where i belongs to [x..z]
,k
是范围的长度
现在,对于“前一个”第m个成员。 可以通过计算(或更直观地表达,“到达”)前一个第m个数字位置(伪代码)来找到前一个数字:
prev(m, i) = (i + len(range) - m) % len(range)
例如,如果你取第10个的前一个,那么
prev(1,10) = (10+10-1)%10 = 19%10 = 9
前3号,数字5 = prev(3,5) = (5+10-3)%10 = 12%10 = 2
。
Etcetera,etcetera。
非常简单,优雅,呵呵?
这里唯一需要注意的是if i == m
,模数将为零,因此在next()和prev()函数中需要一个处理机制。
希望这有帮助, 雅各
答案 4 :(得分:1)
您可能会查看Tie::Cycle的来源,这是我创建的模块,用于遍历任意列表。
请记住,数字实际上只是代表某些东西的字形。如果你有这些字形的Perl列表,你仍然有一个从零开始的序列,因为你对列表索引进行了数学运算,而不是字形。当您选择了正确的列表索引时,可以使用该索引处的元素。
如果你想要非常大的列表或懒惰列表,你仍然可以这样做,但你只需要做更多的工作。
答案 5 :(得分:0)
我在R中有此解决方案:
pred <- function(n) n - 1L # cf. Pascal's pred
succ <- function(n) n + 1L # cf. Pascal's succ
`%mod1%` <- function(m, n) succ(pred(m) %% n) # modulo from 1
cat(-11:24 %mod1% 12) # test
# 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12
答案 6 :(得分:0)
假设你想从 1 映射到 n 而不是 0 映射到 n-1 例如 n=5,范围 1 到 x,结果 0 到 4,0mod5=0 1mod5=1, 2mod5=2... xmod5 结果 0 每当x=5*k。使用 ((x-1)mod5)+1,x 必须 >0。这将始终映射(计数)在 1 到 5 范围内,而不是 0 到 4。