Pergunta

Não é realmente recebendo a ponto da função de mapa. Alguém pode explicar com exemplos seu uso?

Existem quaisquer benefícios de desempenho para usar isso em vez de um loop ou é apenas açúcar?

Foi útil?

Solução

Toda vez que você deseja gerar uma lista baseada outra lista:

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

Uma vez que as listas são pairwise facilmente convertida em hashes, se você quiser uma tabela hash para objetos com base em um determinado atributo:

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

É uma ferramenta de uso realmente geral, você tem que basta começar a usá-lo para encontrar bons usos em suas aplicações.

Alguns podem preferir detalhado looping código para fins de legibilidade, mas, pessoalmente, acho map mais legível.

Outras dicas

Antes de tudo, é uma maneira simples de transformar um array:. Ao invés de dizer por exemplo

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

Você pode dizer

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

Também é útil para a criação de uma tabela de consulta rápida:., Em vez de por exemplo

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

você poderia dizer

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

Também é útil se você quiser lista um derive de outra, mas particularmente não precisa ter uma variável temporária atravancando o lugar, por exemplo, em vez de

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);

você diz que o muito mais simples

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

(Edit: fixa os desaparecidos "chaves% params" nessa última linha)

A função map é usada para transformar listas. É basicamente açúcar sintático para a substituição de certos tipos de loops for[each]. Depois de quebrar a cabeça em torno dele, você verá usos para ele em todos os lugares:

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

Veja também a Schwartziana transformar para uso avançado de mapa.

Também é útil para fazer hashes de pesquisa:

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

é equivalente a

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

Não há muito poupança lá, mas suponha que você queira definir %is_US_state?

Mapa é usado para criar uma lista, transformando os elementos da outra lista.

grep é usado para criar uma lista filtrando elementos da outra lista.

tipo é usado para criar uma lista classificando os elementos da outra lista.

Cada um destes operadores recebe um bloco de código (ou de uma expressão) que é utilizado para transformar, filtro ou elementos de comparar a lista.

Para Mapa , o resultado do bloco torna-se um (ou mais) elemento (s) na nova lista. O elemento atual é alias para $ _.

Para grep , o resultado boolean do bloco decide se o elemento da lista original será copiado para a nova lista. O elemento atual é alias para $ _.

Para tipo , o bloco recebe dois elementos (alias a $ a $ e b) e é esperado para retornar uma de -1, 0 ou 1, indicando se $ a é maior, igual ou menos de US $ b.

O Schwartziana Transform usa esses operadores de forma eficiente de cache valores (propriedades) para ser usada na triagem uma lista, especialmente no cálculo dessas propriedades tem um custo não-trivial.

Ele funciona através da criação de uma matriz intermediária que tem como referência os elementos de matriz com o elemento original e o valor calculado pela qual deseja classificar. Esta matriz é passado para classificar, que compara os valores já computados, criando outra matriz intermediária (este é ordenada) que por sua vez é passado para outro mapa, que joga fora os valores em cache, restaurando assim a matriz aos seus elementos lista inicial (mas na ordem desejada agora).

Exemplo (cria uma lista de arquivos no diretório atual classificadas pelo tempo de sua última modificação):

@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;

Por encadeamento dos operadores em conjunto, não é necessária nenhuma declaração de variáveis ??para as matrizes intermediárias;

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

Você também pode filtrar a lista antes de classificar através da inserção de um grep (se você quiser filtro no mesmo valor em cache):

Exemplo (uma lista dos arquivos modificados nas últimas 24 horas classificados o último tempo de modificação):

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

A função de mapa é executado uma expressão em cada elemento de uma lista, e retorna os resultados da lista. Vamos dizer que eu tinha a seguinte lista

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

e eu queria capitalizar a primeira letra de cada um desses nomes. Eu poderia loop através deles e chamar ucfirst de cada elemento, ou eu poderia simplesmente fazer o seguinte

@names = map (ucfirst, @names);

A função de mapa é uma ideia do paradigma de programação funcional. Na programação funcional, funções são objetos de primeira classe, o que significa que eles podem ser passados ??como argumentos para outras funções. Mapa é um simples, mas um exemplo muito útil deste. Ele toma como seus argumentos uma função (vamos chamá-lo f) e uma lista l. f tem que ser uma função recebendo um argumento, e mapear simplesmente aplica f a cada elemento da lista l. f pode fazer o que precisa fazer para cada elemento:. adicionar um para cada elemento, quadrado cada elemento, escrever todos os elementos para um banco de dados, ou abra uma janela do navegador web para cada elemento, que passa a ser uma URL válida

A vantagem de usar map é que ele muito bem encapsula iteração sobre os elementos da lista. Tudo que você tem a fazer é dizer "fazer f a cada elemento, e é até map para decidir a melhor forma de fazer isso. Por exemplo map pode ser implementado para dividir o seu trabalho entre os vários segmentos, e seria totalmente transparente para o chamador.

Note, que map não é nada específico para Perl. É uma técnica padrão usado por linguagens funcionais. Ele pode até mesmo ser implementado em C usando ponteiros de função, ou em C ++ utilizando "objetos de função".

"açúcar Just" é dura. Lembre-se, um loop é apenas açúcar -. Se de e Goto pode fazer construções tudo laço fazer e mais

Mapa é uma função nível alto o suficiente que ele ajuda a manter operações muito mais complexas em sua cabeça, então você pode codificar e depurar problemas maiores.

Para paráfrase "Effective Perl Programming" por Hall & Schwartz, mapa pode ser abusado, mas acho que é melhor usado para criar uma nova lista a partir de uma lista existente.

Crie uma lista dos quadrados de 3,2, e 1:

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

Gerar senha:

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

Você usa mapa para transformar uma lista e atribuir os resultados a outra lista, grep para filtrar uma lista e atribuir os resultados a outra lista. A lista "outro" pode ser a mesma variável como a lista que você está transformando / filtragem.

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

É hora usado você gostaria de criar uma nova lista a partir de uma lista existente.

Por exemplo, você pode mapear uma função de análise em uma lista de strings para convertê-los em números inteiros.

Ele permite que você para transformar uma lista como uma expressão em vez de declarações . Imagine que um hash de soldados definido assim:

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

então você pode operar na lista de nomes separadamente.

Por exemplo,

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

é uma expressão . Ele pode ir a qualquer lugar uma expressão é permitida - exceto que você não pode atribuir a ele.

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

índices da matriz, tendo a max.

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

Eu acho que uma das vantagens de expressões operacionais é que ele reduz os erros que vêm de variáveis ??temporárias.

Se o Sr. McCoy quer filtrar todos os Hatfields para consideração, você pode adicionar essa verificação com o mínimo de codificação.

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

eu possa continuar encadeamento estes expressão de modo que se a minha interação com esses dados tem que chegar no fundo para um propósito particular, eu não tenho que escrever um monte de código que finge eu vou fazer muito mais.

Como já foi dito, mapa cria listas de listas. Pense em "mapeamento" o conteúdo de uma lista para outra. Aqui está um código de um programa CGI para tomar uma lista de números de patentes e hiperlinks de impressão para os pedidos de patentes:

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);

Como já foi dito, mapa é mais útil para transformar uma lista. O que não foi mencionado é a diferença entre mapa e um "equivalente" para loop.

Uma diferença é que para não funciona bem para uma expressão que modifica a lista a iteração sobre. Um desses termina, eo outro não:

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

Outra pequena diferença é que o contexto dentro do bloco de mapa é um contexto de lista, mas o para Imparts de loop um contexto vazio.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top