3

ここに私の問題があります:私は2つのアレイを持っています。1つは文字配列で、スライディングウィンドウを表します。文字は最初からシフトされ、最後にプッシュされます。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;

言い換えると、配列スライスへの参照を持つ2番目の配列を使用できるようにしたいと思います(たとえば、Cのポインター配列で行うように)。

Perlでこれを行う慣用的な方法はありますか?

更新:これは、高速テキスト検索を実行するためのより大きなプログラムの一部です。私は参照のハッシュを使用するつもりでした(たとえば、非常に遅い「index」関数の代わりに。そして、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

実際、charsについて実際に話している場合、左辺値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池上はそれが実行可能な選択肢かもしれないと指摘した。次のソリューションには、実際に配列を使用するという美しさはありませんが、charの配列の代わりに、文字列を使用します。これは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 に答える