3

这是我的问题:我有 2 个数组。一个是字符数组,代表一个滑动窗口。字符从一开始就被转移并在最后被推动。我想使用第二个数组来存储对在字符移动时“跟随”字符的数组切片的引用。例子:

my @char_array = ('h','e','l','l','o','w','o','r','l','d');
my $char_arr_ref=[@char_array[1..$#char_array]]; 
print @$char_arr_ref, "\n"; # slice contains 'elloworld';
shift(@char_array);
push(@char_array), 'x';
print @$char_arr_ref, "\n"; # slice still contains 'elloworld', not 'lloworldx' as I need;

换句话说,我希望能够使用引用数组切片的第二个数组(例如,我会使用 C 中的指针数组)。

在 Perl 中有没有一种惯用的方法来做到这一点?

更新:这是进行快速文本搜索的大型程序的一部分。我打算使用引用哈希(例如,而不是非常缓慢的“索引”函数。我需要在 Perl 中执行此操作。

4

3 回答 3

8

在 C 中,您的窗口可能使用指针算法来实现。

const char* s = str+1;
const char* e = str+len;
for (const char* p=s; p!=e; ++p) putc(*p);

除了指针算法不允许您调整缓冲区 ( push @char_array, 'x';) 的大小。即使在 C 中,您也必须使用偏移量。

size_t si = 1;
size_t ei = len;
for (size_t i=si; i!=e1; ++i) putc(str[i]);

这是幸运的,因为 Perl 没有指针,更不用说指针运算了。但是抵消?没问题!

my @char_array = split //, 'helloworld';
my ($s, $e) = (1, $#char_array);
say @char_array[$s..$e];    # elloworld
shift @char_array;
push @char_array, 'x';
say @char_array[$s..$e];    # lloworldx

如果我们实际上是在谈论字符,那么字符串会更有效。

my $char_array = 'helloworld';
my ($s, $e) = (1, length($char_array));
say substr($char_array, $s, $e-$s+1);    # elloworld
$char_array =~ s/^.//s;
$char_array .= 'x';
say substr($char_array, $s, $e-$s+1);    # lloworldx

事实上,如果我们真的在谈论字符,我们很幸运,因为我们可以使用左值 substr 并让 Perl 为我们处理偏移量!

my $char_array = 'helloworld';
my $substr_ref = \substr($char_array, 1, length($char_array)-1);
say $$substr_ref;        # elloworld
$char_array =~ s/^.//s;
$char_array .= 'x';
say $$substr_ref;        # lloworldx

比 C 更容易,或多或少都有相同的好处!

于 2013-01-16T08:43:52.807 回答
2

我不确定你在做什么,我怀疑它是否适合“快速文本搜索”程序。但是,您可以通过使用简单的子例程而不是引用来完成您想要的:

#!usr/bin/perl
use strict;
use warnings;

my @char_array = ('h','e','l','l','o','w','o','r','l','d');
sub char_arr_slice { return @char_array[1..$#char_array] };

print char_arr_slice, "\n"; 

shift(@char_array);
push(@char_array, 'x');

print char_arr_slice, "\n";

注意:为什么我有我的怀疑?因为字符数组很少是在 Perl 中处理字符串的正确方法。与使用 Perl 的内置字符串处理工具(尤其是正则表达式)相比,这种方法可能效率较低且笨拙得多。

于 2013-01-16T08:26:46.970 回答
2

这是一个使用重载对象的实现:

#!/usr/bin/perl
use strict; use warnings; use feature 'say';

my @array = qw( H e l l o W o r l d );
my $window = SlidingWindow->new(\@array, 1, -1);
say "@$window";
shift @array;
push @array, "x";
say "@$window";

{
    package SlidingWindow;
    use overload '@{}' => sub {
        my ($self) = @_;
        # manage negative indices
        my $min = $self->{min} >= 0 ? $self->{min}
                                    : $#{ $self->{array} } + 1 + $self->{min};
        my $max = $self->{max} >= 0 ? $self->{max}
                                    : $#{ $self->{array} } + 1 + $self->{max};
        return +[ @{ $self->{array} }[$min .. $max] ];
    };
    sub new {
        my ($class, $arrayref, $min, $max) = @_;
        return bless +{
            array => $arrayref,
            min => $min,
            max => $max,
        } => $class;
    }
}

输出:

e l l o W o r l d
l l o W o r l d x

当然,您有方法调用的开销,但 Perl 根本没有指针。如果你抱怨index太慢(不能更快),你只能改进你的算法,而不是你的实现。

更新

池上指出,这substr可能是一个可行的选择。以下解决方案没有实际使用数组的美感,而是我们使用字符串而不是字符数组。这在 Perl 中是不一样的:字符串的效率要高得多。

my $charray = "HelloWorld";
say substr($charray, 1);
substr($charray, 0, 1) = "";
$charray .= "x";
say substr($charray, 1);

输出:

elloWorld
lloWorldx
于 2013-01-16T08:42:37.857 回答