47

これに対する解決策は非常に単純だと思いますが、しばらく考えていて、エレガントな解決策を思いつくことができませんでした。

私は数字の範囲を持っています。たとえば1..10 = (1,2,3,4,5,6,7,8,9,10)、これは円形です。つまり、最後の数字の後の数字が最初の数字 ( next(10)=1) になります。

範囲内の特定の数値について、次の数値と前の数値i>0を計算したいと思います。例えば。mmnext(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)%nnn=10prev

4

7 に答える 7

63

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 では modulo は常に正の値を返します (少なくとも 2 番目のオペランドが正の整数の場合)。基本的に、それはあなたが望むことをします。したがって、次のように記述して を省略できます+ $_[2]

sub nxt { ($_[0] + $_[1] - 1) % $_[2] + 1; }
sub prv { ($_[0] - $_[1] - 1) % $_[2] + 1; }
于 2010-09-27T11:39:16.157 に答える
16

とにかくあなたnext = (i + m) % nは正しくありません-場合によってはゼロを返します。

代わりにこれを試してください:

next(i, m) = ((i - 1) + m) % n + 1
prev(i, m) = ((i - 1) + n - m) % n + 1

実際には、1 つ削除してから、正しい値を見つけてから、もう一度追加します。

の場合、最初にprev追加nして、負の数の剰余を取らないようにします

于 2010-09-27T11:38:26.547 に答える
3

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
于 2010-09-27T12:15:57.843 に答える
2

よろしければ、一般的に最初にいくつかの言葉。

「prev」関数を実装する際の混乱は、正と負の整数のドメインでこの問題について考えることから生じます。ジオメトリの観点から考えてみてください。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

番号5の前の3番目= prev(3,5) = (5+10-3)%10 = 12%10 = 2。Etceteraなど。 とてもシンプルでエレガントですね

ここでの唯一の注意点はif i == m、モジュロがゼロになることです。そのため、next()関数とprev()関数の両方でこの結果を処理するメカニズムが必要です。

これがお役に立てば幸いです、ジャス。

于 2010-09-27T12:38:33.277 に答える
1

Tie::Cycleのソースを見ることができます。これは、任意のリストを循環するために私が作成したモジュールです。

数字は実際には何かを表す単なるグリフであることを忘れないでください。これらのグリフの Perl リストがある場合でも、グリフではなくリスト インデックスで計算を行うため、ゼロから始まるシーケンスがあります。適切なリスト インデックスを選択したら、そのインデックスの要素を使用します。

非常に大きなリストや遅延リストが必要な場合でも、これを行うことができますが、もう少し作業を行う必要があります。

于 2010-09-27T15:28:32.127 に答える