13 Stimmen

Gibt es eine Möglichkeit, ein Slice zum Ende eines anonymen Arrays in Perl zu greifen?

Das hat mich in der letzten halben Stunde völlig aus dem Konzept gebracht. Gibt es eine Möglichkeit für mich, ein Array-Slice an das Ende eines anonymen Arrays zu greifen? Ich habe es versucht:

(split(' ',$test_line))[1..$#_]

und ich habe es versucht: (split(' ',$test_line))[1..-1]

aber ärgerlicherweise funktioniert nichts davon. Ich möchte wirklich nicht eine zusätzliche temporäre Variable instanziiert, um die Zwischen-Array (die ich nicht brauche) haben. Und ich möchte wirklich nicht eine hässliche und unleserliche One-Liner verwenden (fand ein paar von denen online). Gibt es wirklich keine geradlinigen Weg, dies zu tun?

15voto

Eric Strom Punkte 39363

Eine Liste, wie Sie sie in Ihrem Beispiel haben, kann nicht vom Ende her zerschnitten werden. Das liegt hauptsächlich daran, dass Listen in Perl keine richtigen Datenstrukturen sind, sondern eher ein Konstrukt, das der Interpreter verwendet, um Daten zu verschieben. Da Sie also wissen, dass Sie eine Liste nur von Anfang an zerschneiden können, haben Sie folgende Möglichkeiten: Entweder Sie legen die Liste in eine Array-Variable und zerschneiden sie dann, Sie ändern Ihren Algorithmus, um das Gewünschte zurückzugeben, oder Sie machen folgendes:

Wenn Sie diesen Wert einer Sache zuordnen, können Sie undef in jedem Steckplatz, den Sie nicht wollen:

 my (undef, @list) = split ' ' => $test_line;

Wenn Sie mehr Code posten, kann ich ihn überarbeiten.

Alternativ können Sie auch einige Werkzeuge aus der funktionalen Programmierung verwenden. Das Funktionspaar drop y take kann nützlich sein, um die Größe einer Liste ohne zusätzliche Variablen zu ändern:

sub take {
    my $n = shift;
    @_[0..$n-1]
}
sub drop {
    my $n = shift;
    @_[$n..$#_]
}

und dann wird Ihr Beispiel zu

drop 1, split ' ' => $test_line;

drop 1 wird gemeinhin auch als tail

sub tail {drop 1, @_}

und natürlich, da sie alle so kurz sind, wenn Sie sie einfügen möchten:

sub {shift; @_}->(split ' ' => ...)

6voto

socket puppet Punkte 3161

Als der OP sagte slice dachte ich an splice :

@allTheWordsExceptTheFirstTwo = splice @{[split' ', $test_line]}, 2;
@allExceptTheFirstAndLastTwo = splice @{[split' ', $test_line]}, 2, -2;

3voto

Sinan Ünür Punkte 114993

Sie können negative Bereiche im Array Subscript verwenden, um eine beliebige Anzahl von Elementen vom Ende her anzusprechen:

my $x = join ' ' => 'a' .. 'z';
my @x = (split ' ', $x)[-13 .. -1];

Dazu müssen Sie jedoch die Gesamtzahl der Elemente im Ergebnis von split um nur das erste Element zu eliminieren.

Tritt dies nur an einer Stelle auf, können Sie mit einem do Block sollte funktionieren:

my $x = join ' ', 'a' .. 'z';
my @x = do { my @y = (split ' ', $x); @y[1 .. $#y] };

In Ihrem Fall würde ich die gesamte Operation in ein Unterprogramm auslagern, wenn sie häufig verwendet werden soll, und die Zeichenfolge anstelle des Ergebnisses der split an das Unterprogramm (kann weiter verallgemeinert werden, indem man dem Benutzer erlaubt, auch das Aufteilungsmuster zu übergeben:

my $x = join ' ', 'a' .. 'g';
my @x = skip_first_n_from_split(3, $x);

print Dump \@x;

sub skip_first_n_from_split {
    my ($n, $x) = @_;
    my @y = split ' ', $x;
    return @y[$n .. $#y];
}

Spaß haben:

#!/usr/bin/perl

use strict; use warnings;

my $x = join ' ', 1 .. 8;
my @skippers = map make_skipper(' ', $_), 0 .. 7;

print "@$_\n" for map $_->($x), @skippers;

sub make_skipper {
    my ($pattern, $n) = @_;

    return sub {
        my $string = shift;
        my $i = 0;
        return [ grep $i++ >= $n, split $pattern, $string ];
    }
}

Ausgabe:

1 2 3 4 5 6 7 8
2 3 4 5 6 7 8
3 4 5 6 7 8
4 5 6 7 8
5 6 7 8
6 7 8
7 8
8

2voto

Sean Punkte 28106

Ich glaube nicht, dass man einen Index für das letzte Element eines beliebigen Listenausdrucks angeben kann, aber wie wäre es mit:

split(' ', (split ' ', $test_line, 2)[1])

Übrigens gibt es hier (oder in Ihrer ursprünglichen Frage) keine anonymen Arrays, sondern nur Listen.

2voto

MkV Punkte 3018

Dies wurde gerade antwortete Ordentlich" auf Perlmonks von BrowserUK, das ist, was Sie tun würden:

my @slice =  sub{ @_[1..$#_] }->( split ' ', $test_line );

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X