Frage

Ich verstehe den Sinn der Kartenfunktion nicht wirklich.Kann jemand anhand von Beispielen die Verwendung erklären?

Gibt es irgendwelche Leistungsvorteile, wenn man dies anstelle einer Schleife verwendet, oder ist es nur Zucker?

War es hilfreich?

Lösung

Jedes Mal, wenn Sie eine Liste erzeugen, basiert eine weitere Liste:

# Double all elements of a list
my @double = map { $_ * 2 } (1,2,3,4,5);
# @double = (2,4,6,8,10);

Da Listen leicht paarweise in Hashes umgewandelt, wenn Sie eine Hash-Tabelle wollen Objekte auf einem bestimmten Attribut basiert:

# @user_objects is a list of objects having a unique_id() method
my %users = map { $_->unique_id() => $_ } @user_objects;
# %users = ( $id => $obj, $id => $obj, ...);

Es ist ein wirklich universelles Werkzeug, müssen Sie nur gute Anwendungen in Ihre Anwendungen finden starten Sie es.

Einige könnten aus Gründen der Lesbarkeit ausführlichen Looping Code bevorzugen, aber ich persönlich finde map besser lesbar.

Andere Tipps

Zunächst einmal ist es eine einfache Art und Weise eine Reihe von Transformation. Anstatt zu sagen z

my @raw_values = (...);
my @derived_values;
for my $value (@raw_values) {
    push (@derived_values, _derived_value($value));
}

Sie können sagen,

my @raw_values = (...);
my @derived_values = map { _derived_value($_) } @raw_values;

Es ist auch nützlich für eine schnelle Lookup-Tabelle aufgebaut. Anstatt z

my $sentence = "...";
my @stopwords = (...);
my @foundstopwords;
for my $word (split(/\s+/, $sentence)) {
    for my $stopword (@stopwords) {
       if ($word eq $stopword) {
           push (@foundstopwords, $word);
       }
    }
}

Sie könnte sagen,

my $sentence = "...";
my @stopwords = (...);
my %is_stopword = map { $_ => 1 } @stopwords;
my @foundstopwords = grep { $is_stopword{$_} } split(/\s+/, $sentence);

Es ist auch nützlich, wenn Sie eine Liste von einem anderen ableiten wollen, müssen aber nicht besonders eine temporäre Variable an die Stelle unübersichtlich haben, z.B. anstatt

my %params = ( username => '...', password => '...', action => $action );
my @parampairs;
for my $param (keys %params) {
    push (@parampairs, $param . '=' . CGI::escape($params{$param}));
}
my $url = $ENV{SCRIPT_NAME} . '?' . join('&', @parampairs);

Sie sagen, die viel einfacher

my %params = ( username => '...', password => '...', action => $action );
my $url = $ENV{SCRIPT_NAME} . '?'
    . join('&', map { $_ . '=' . CGI::escape($params{$_}) } keys %params);

(Edit: fixed den "Schlüssel% params" in der letzten Zeile fehlt)

Die map Funktion wird verwendet, um Listen zu transformieren. Es ist im Grunde syntaktischer Zucker für bestimmte Arten von for[each] Schleifen zu ersetzen. Sobald Sie um es den Kopf wickeln, werden Sie Gebrauch für sie finden überall:

my @uppercase = map { uc } @lowercase;
my @hex       = map { sprintf "0x%x", $_ } @decimal;
my %hash      = map { $_ => 1 } @array;
sub join_csv { join(',', map {'"' . $_ . '"' } @_ }

Siehe auch die Schwartzian verwandeln für erweiterte Nutzung der Karte.

Es ist auch praktisch für die Herstellung von Lookup-Hash-Werten:

my %is_boolean = map { $_ => 1 } qw(true false);

entspricht

my %is_boolean = ( true => 1, false => 1 );

Es gibt nicht viele Einsparungen dort, aber angenommen, Sie wollten %is_US_state definieren?

Karte wird verwendet, um eine Liste zu erstellen, indem die Elemente einer anderen Liste transformiert werden.

grep wird verwendet, um eine Liste zu erstellen, indem Elemente einer anderen Liste gefiltert werden.

Sortieren wird verwendet, um eine Liste zu erstellen, indem die Elemente einer anderen Liste sortiert werden.

Jeder dieser Operatoren erhält einen Codeblock (oder einen Ausdruck), der zum Transformieren, Filtern oder Vergleichen von Elementen der Liste verwendet wird.

Für Karte, wird das Ergebnis des Blocks zu einem (oder mehreren) Element(en) in der neuen Liste.Das aktuelle Element hat den Alias ​​$_.

Für grep, das boolesche Ergebnis des Blocks entscheidet, ob das Element der ursprünglichen Liste in die neue Liste kopiert wird.Das aktuelle Element hat den Alias ​​$_.

Für Sortieren, empfängt der Block zwei Elemente (mit dem Alias ​​$a und $b) und soll entweder -1, 0 oder 1 zurückgeben, was angibt, ob $a größer, gleich oder kleiner als $b ist.

Der Schwartzsche Transformation verwendet diese Operatoren, um Werte (Eigenschaften) effizient zwischenzuspeichern, die beim Sortieren einer Liste verwendet werden sollen, insbesondere wenn die Berechnung dieser Eigenschaften mit nicht trivialen Kosten verbunden ist.

Es funktioniert durch die Erstellung eines Zwischenarrays, das als Elemente Array-Referenzen mit dem Originalelement und dem berechneten Wert enthält, nach dem wir sortieren möchten.Dieses Array wird an sort übergeben, das die bereits berechneten Werte vergleicht und ein weiteres Zwischenarray erstellt (dieses wird sortiert), das wiederum an eine andere Map übergeben wird, die die zwischengespeicherten Werte verwirft und so das Array auf seine ursprünglichen Listenelemente zurücksetzt (aber). nun in der gewünschten Reihenfolge).

Beispiel (erstellt eine Liste der Dateien im aktuellen Verzeichnis, sortiert nach dem Zeitpunkt ihrer letzten Änderung):

@file_list = glob('*');
@file_modify_times = map { [ $_, (stat($_))[8] ] } @file_list;
@files_sorted_by_mtime = sort { $a->[1] <=> $b->[1] } @file_modify_times;
@sorted_files = map { $_->[0] } @files_sorted_by_mtime;

Durch die Verkettung der Operatoren ist für die Zwischenarrays keine Variablendeklaration erforderlich.

@sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, (stat($_))[8] ] } glob('*');

Sie können die Liste vor dem Sortieren auch filtern, indem Sie ein einfügen grep (wenn Sie nach demselben zwischengespeicherten Wert filtern möchten):

Beispiel (eine Liste der in den letzten 24 Stunden geänderten Dateien, sortiert nach dem Zeitpunkt der letzten Änderung):

    @sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } grep { $_->[1] > (time - 24 * 3600 } map { [ $_, (stat($_))[8] ] } glob('*');

Die Map-Funktion führt einen Ausdruck auf jedes Element einer Liste und gibt die Listenergebnisse. Lets sagen, dass ich die folgende Liste hatte

@names = ("andrew", "bob", "carol" );

, und ich wollte den ersten Buchstaben jeder dieser Namen Kapital zu schlagen. Ich konnte Schleife durch sie und rufen ucfirst jedes Elements, oder ich könnte die folgende

gerade tun
@names = map (ucfirst, @names);

Die Map-Funktion ist eine Idee von dem funktionalen Programmierparadigma. In der funktionalen Programmierung, sind Funktionen, Objekte erster Klasse, was bedeutet, dass sie als Argumente an andere Funktionen übergeben werden können. Karte ist ein einfaches, aber ein sehr nützliches Beispiel. Es nimmt als Argument eine Funktion (läßt es f nennen) und eine Liste l. f muss eine Funktion ein Argument nehmen, und Karte einfach gilt f zu jedem Element der Liste l. f können tun, was Sie zu jedem Element getan brauchen. fügen Sie ein zu jedem Element, quadratisch jedes Element, schreiben jedes Element in eine Datenbank oder ein Fenster Web-Browser für jedes Element öffnen, die eine gültige URL sein geschieht

Der Vorteil map der ist, dass es schön Iterieren über die Elemente der Liste kapselt. Alles, was Sie tun müssen, ist „tun zu sagen f zu jedem Elemente, und es ist am besten zu map zu entscheiden, wie das zu tun. Zum Beispiel map implementiert werden kann, seine Arbeit unter mehreren Threads aufgeteilt, und es wäre völlig transparent sein, der Anrufer.

Beachten Sie, dass map überhaupt nicht spezifisch für Perl. Es ist eine Standard-Technik, die von funktionalen Sprachen verwendet. Es kann sogar in C unter Verwendung von Funktionszeigern oder in C ++ implementiert wird „Funktionsobjekte“ verwendet wird.

"Just Zucker" ist hart. Denken Sie daran, eine Schleife ist nur Zucker -. Wenn und geht zu können alles Schleifenkonstrukte tun tun und mehr

Karte ist eine ausreichend hohe Level-Funktion, die es Ihnen halten viel komplexere Operationen im Kopf hilft, so können Sie Code und Probleme debug größer.

Um "Effective Perl Programming" von Hall & Schwartz paraphrasieren, Karte kann missbraucht werden, aber ich denke, dass es am besten benutzt, um eine neue Liste aus einer bestehenden Liste zu erstellen.

Erstellen Sie eine Liste der Quadrate von 3,2, & 1:

@numbers = (3,2,1);
@squares = map { $_ ** 2 } @numbers;

generieren Kennwort:

$ perl -E'say map {chr(32 + 95 * rand)} 1..16'
# -> j'k=$^o7\l'yi28G

Sie Karte verwenden, um eine Liste zu transformieren und die Ergebnisse in einer anderen Liste zuweisen, grep eine Liste zu filtern und die Ergebnisse in einer anderen Liste zuweisen. Die „andere“ -Liste die gleiche Variable wie die Liste sein können Sie transformieren / Filterung.

my @array = ( 1..5 );
@array = map { $_+5 } @array;
print "@array\n";
@array = grep { $_ < 7 } @array;
print "@array\n";

Es wird verwendet, zu jeder Zeit möchten Sie eine neue Liste aus einer bestehenden Liste erstellen.

Zum Beispiel Sie eine Parsing-Funktion auf eine Liste von Zeichenketten abbilden konnte sie auf ganze Zahlen zu konvertieren.

Es erlaubt Ihnen, eine Liste als Ausdruck nicht in Aussagen zu transformieren. Stellen Sie sich einen Hash von Soldaten definiert wie folgt:

{ name          => 'John Smith'
, rank          => 'Lieutenant'
, serial_number => '382-293937-20'
};

, dann können Sie auf der Liste der Namen separat betrieben werden.

Beispiel:

map { $_->{name} } values %soldiers

ist ein Ausdruck . Es kann überall hin ein Ausdruck erlaubt ist - außer Sie es nicht zuordnen können.

${[ sort map { $_->{name} } values %soldiers ]}[-1]

Indizes der Array, wobei die max.

my %soldiers_by_sn = map { $->{serial_number} => $_ } values %soldiers;

Ich finde, dass einer der Vorteile der operativen Ausdrücke ist, dass es auf die Bugs schneidet sich, die von temporären Variablen kommen.

Wenn Herr McCoy will die Hatfields alle für die Prüfung, um herauszufiltern, können Sie, dass der Check mit minimalen Codierung hinzufügen.

my %soldiers_by_sn 
    = map  { $->{serial_number}, $_ } 
      grep { $_->{name} !~ m/Hatfield$/ } 
      values %soldiers
      ;

Ich kann diese Verkettungs Ausdruck weiterhin so, dass, wenn meine Interaktion mit diesen Daten tief zu erreichen hat für einen bestimmten Zweck, ich habe nicht viel Code zu schreiben, der vorgibt, ich werde viel mehr tun.

Wie andere gesagt haben, Karte erstellt Listen von Listen. Denken Sie an „Mapping“ der Inhalt einer Liste in einer anderen. Hier ist ein Code aus einem CGI-Programm eine Liste von Patentnummern und Druck Hyperlinks zu den Patentanmeldungen zu übernehmen:

my @patents = ('7,120,721', '6,809,505', '7,194,673');
print join(", ", map { "<a href=\"http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL&p=1&u=/netahtml/srchnum.htm&r=0&f=S&l=50&TERM1=$_\">$_</a>" } @patents);

Wie andere gesagt haben, Karte ist sehr nützlich für eine Liste zu verwandeln. Was wurde nicht erwähnt wird, ist die Differenz zwischen der Karte und einem „Äquivalent“ for-Schleife.

Ein Unterschied besteht darin, dass für nicht gut für einen Ausdruck funktioniert, der die Liste über die Iteration ändert. Einer dieser endet, und der andere nicht:

perl -e '@x=("x"); map { push @x, $_ } @x'
perl -e '@x=("x"); push @x, $_ for @x'

Ein weiterer kleiner Unterschied besteht darin, dass die Kontext in der Karte Block ist eine Liste Kontext, aber der for-Schleife verleiht einen leeren Kontext.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top