2009-10-19 10 views
1

J'essaie de réduire le nombre de lignes de code que j'utilise mais je me retrouve avec un problème assez simple (même si ça me bouscule depuis que je commence juste à envelopper mes références)Pourquoi cette carte renvoie-t-elle un seul nombre?

J'essaie concaténer plusieurs valeurs dans un ordre particulier .. Mon code ressemble à ceci ..

my $separator = ":"; 
my @vals = qw(name last-name first-name phone); 
my $return_name; 
$return_name = map { 
    $return_name = $return_name . $query->param($_) . $separator 
} @vals; 

ce que je reçois est « 4 », au lieu de concantenating tout en une seule chaîne.

Ce que je suis en train de réaliser est une version plus courte de ...

$return_name = $query->param('name') . 
    $separator . $query->param('last-name') . 
    $separator . $query->param('first_name') . 
    $separator . $query->param('phone'); 

(je suis en train d'essayer d'enchaîner 25 $query->params. Je ne donnait quatre par souci de concision)

Répondre

4

Une partie de votre problème est la confusion sur la façon dont map fonctionne.

map prend une liste d'arguments, effectue une opération sur les éléments de la liste et crée une nouvelle liste à partir des résultats. Dans un contexte scalaire, il renvoie le nombre de membres dans la nouvelle liste.

Dans la plupart des cas, vous ne souhaitez pas effectuer d'affectation dans l'opération map.

# no assignment needed to set @foo 
my @foo = map $_+2, 1,2,3; 
# @foo = (3,4,5); 

Le seul endroit où l'affectation logique est si vous avez besoin d'utiliser une opération qui devrait normalement changer la valeur de $_, mais vous devez conserver les arguments à la carte sans changement.

Cette explication n'est pas très claire. Consultez ces exemples, ils devraient aider à clarifier ce que je dis. La première vous montre carte peut modifier les valeurs qu'il traite:

my @foo = qw(fee fie foe fum); 
my @bar = map { s/e/-/g } @foo; 
# @foo = ('f--', 'fi-', 'fo-', 'fum'); 
# @bar = (2, 1, 1, ''); 

Pour éviter de modifier @foo que vous pouvez faire:

my @foo = qw(fee fie foe fum); 
my @bar = map { my $val = $_; $val =~ s/e/-/g } @foo; 
# @foo = ('fee', 'fie', 'foe', 'fum'); 
# @bar = ('f--', 'fi-', 'fo-', 'fum'); 

Ou vous pouvez faire:

utilisation Liste :: moreutils QW (appliquer);

my @foo = qw(fee fie foe fum); 
my @bar = apply { s/e/-/g } @foo; 
# @foo = ('fee', 'fie', 'foe', 'fum'); 
# @bar = ('f--', 'fi-', 'fo-', 'fum'); 

à son plus map de base fonctionne comme une forme spécialisée d'une boucle for. Les deux morceaux de code produisent exactement le même résultat:

my @foo = map {$_ * 2} 1..5; 

my @bar; 
for (1..5) { 
    my $val = $_ * 2; 
    push @bar, $val; 
} 

J'espère que ce que vous avez donné un peu d'aide pour apprendre à penser à map. Une fois que vous avez appris à l'utiliser (et les constructions connexes comme grep et apply), vous serez en mesure d'exprimer de manière concise des idées qui peuvent incroyablement verbeux lorsqu'il est construit en utilisant le code de bouclage normal.

+0

daotoad, c'était la meilleure réponse que j'aurais pu obtenir pour ça. Je veux dire que tout le monde a été incroyablement utile mais votre réponse m'a vraiment aidé à le comprendre. – Nikki

3

Essayez ceci:

join $separator, 
    map { $query->param($_) } 
    ("name", "last-name", "first-name", "phone"); 

pour répondre à la raison pour laquelle vous obtenez « 4 », c'est parce que vous assignez les tableaux résultant de la cardinalité à un scalaire.

4

map renvoie une liste, pas une chaîne. Essayez ceci:

$return_name = join $separator, map { $query->param($_) } @vals; 

Ou si vous voulez vraiment réduire le nombre de lignes, essayez ceci:

my $return_name = join ':', 
    map { $query->param($_) } 
    qw(name last-name first-name phone); 

(. La version d'une ligne a été inspiré par la réponse de dsm)

+0

Je suis sûr que dsm a travaillé aussi. jbourque ça marche comme un champion! Merci! – Nikki

4
$return_name = map { $return_name = $return_name . $query->param($_) . $separator } @vals; 

C'est une affectation scalaire, qui donne le contexte scalaire de l'opération de carte. map dans un contexte scalaire renvoie le nombre d'éléments qui auraient été produits.

Bien que cette ligne de code particulier crie pour l'utilisation de join(), si vous venez d'un arrière-plan de la programmation fonctionnelle, vous pouvez être plus à l'aise avec réduction:

use List::Util 'reduce'; 
$return_name = reduce { $a . $query->param($b) . $separator } "", @vals; 
1

En plus de toutes les bonnes réponses que vous ont reçu, notez que

$return_name = $return_name . $query->param($_) . $separator; 

peut être écrit comme

$return_name .= $query->param($_) . $separator; 
Questions connexes