如何迭代"循环数组"中的子范围?

Dav*_*d B 1 arrays perl range cycle

我正在尝试编写以下perl子例程.给定的是a长度数组,数组中n的索引i(0<=i<n上游窗口长度u和下游窗口长度)d.

我想迭代上游窗口和下游窗口中的值i.在最简单的情况下,这将迭代a[i-u..i-1](上游窗口)和a[i+1..i+d](下游窗口)中的值.

例如:如果我的数组是1 2 3 4 5 6 7 8 9 10,i=5并且两个窗口大小都是2,则上游值是简单的6 7,下游值是9 10.

但是,有两个并发症:

  1. 我想我的数组是循环的.如果i相对较小(接近0)或较大(接近n),则其中一个窗口可能不适合阵列.在这种情况下,我想将数组看作循环数组.例如,如果我的数组是1 2 3 4 5 6 7 8 9 10,i=8并且两个窗口大小都是4,则上游值是简单4 5 6 7但下游值是9 10 1 2.

  2. 我宁愿用某种方法迭代这些值而不将它们显式复制到新数组中,因为它们可能很长.

Cha*_*ens 6

您可以使用范围运算符(..)通过减去上游窗口$i并添加下游窗口来获取标记列表$i.$i如果你不想要那个$i值,你需要记住在迭代器等于时跳过迭代器.

您将需要使用模运算符(%)来将索引保持在数组的边界内.给定一个大小的数组11,我们可以看到通过使用11它修改索引将始终指向数组中的正确位置:

#!/usr/bin/perl

use strict;
use warnings;

for my $i (-22 .. 22) {
    print "$i => ", $i % 11, "\n";
}
Run Code Online (Sandbox Code Playgroud)

您可能会遇到大量问题(即数字大于您的平台在无符号整数中所包含的数字),因为Perl 5会更改模数在那里使用的算法.它变得更像C fmod(但有一些差异).

您可能还想不使用该integer编译指示.它会%更快,但你得到C模运算符的行为.ANSI和ISO都没有定义C应该对负数做什么,所以你可能会或者可能不会得到有效的索引.当然,只要C的版本吐出来

X   -5 -4 -3 -2 -1 0 1
X%5  0 -4 -3 -2 -1 0 1
Run Code Online (Sandbox Code Playgroud)

要么

X   -5 -4 -3 -2 -1 0 1
X%5  0  1  2  3  4 0 1
Run Code Online (Sandbox Code Playgroud)

它应该没问题(如果不是非常便携).

看起来C99定义了模运算符来返回第二种情况,只要perl用C99编译器编译(打开C99标志),使用integerpragma 应该是安全的.