什么是Perl的地图呢?(What's the point of Perl's ma

2019-07-04 06:02发布

没有真正得到地图功能的点。 任何人都可以用例子说明它的用途?

有没有使用这种替代循环的任何性能优势还是只是糖吗?

Answer 1:

任何时候你要基于另一个列表列表:

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

由于名单很容易转化成对成哈希值,如果你想为基于特定属性对象的哈希表:

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

这是一个非常通用的工具,你必须只是开始使用它来找到你的应用程序很好的用途。

有的人可能喜欢冗长的循环代码可读性目的,但就个人而言,我发现map更具可读性。



Answer 2:

首先,它的转化数组的一个简单的方法:与其说如

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

你可以说

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

它也是建立一个快速查找表有用:而不是如

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

你可以说

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

这也是有用的,如果你想从另一个派生一个列表,但并不特别需要有一个临时变量弄乱的地方,例如,而不是

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

你说的更简单

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

(编辑:固定在最后一行失踪“键%PARAMS”)



Answer 3:

map功能用于改造名单。 它基本上是更换某些类型的复合糖for[each]循环。 一旦你环绕它你的头,你到处都会看到它的用途:

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


Answer 4:

另见的Schwartzian变换在地图的高级用法。



Answer 5:

这也是非常方便的查找哈希:

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

相当于

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

没有太多的积蓄有,但假设你想定义%is_US_state



Answer 6:

地图是用来通过将另一个列表中的元素创建列表。

grep的用于通过过滤另一个列表的元素来创建列表。

排序是通过使用另一种排序列表的元素来创建列表。

这些运算符的接收被用于转化,过滤器或比较列表中元素的码块(或表达)。

对于地图 ,该块的结果变为在新的列表中的一个(或多个)元件(一个或多个)。 当前元素的别名为$ _。

对于grep的 ,块的布尔结果决定是否原始列表的元素将被复制到新的列表。 当前元素的别名为$ _。

对于排序 ,块接收两个元件(别名为$ a和$ b)和预期返回-1,0或1之一,指示$ a是否大于,等于或小于$ B。

所述的Schwartzian变换使用这些运营商能够有效的缓存值(属性),以在一个分拣列表中使用,尤其是当计算这些性能具有一个非平凡成本。

它的工作原理通过创建具有与原始的元素和元素数组引用由我们要排序的计算值的中间阵列。 这个数组传递进行排序,其比较所述已计算的值,创建另一个中间阵列(这一个排序)继而被传递到另一地图其扔掉缓存值,从而恢复阵列到其初始列表元素(但在所希望的顺序现在)。

示例(创建由他们的最后修改时间排序的当前目录中的文件列表):

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

通过链接运营在一起,需要用于中间阵列没有变量声明;

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

您也可以通过插入的grep(如果你想在同一个缓存值筛选)分选前过滤列表:

实施例(在过去24小时内修改的文件的列表排序的最后修改时间):

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


Answer 7:

地图功能运行列表中的每个元件上的表达,并返回列表结果。 比方说,我有以下列表

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

我想利用这些名字的第一个字母。 我可以遍历他们并呼吁ucfirst每个元素的,我也可以只是做以下

@names = map (ucfirst, @names);


Answer 8:

地图功能是从功能的编程范例的想法。 在函数式编程中,函数是第一类对象,这意味着它们可以作为其他函数的参数进行传递。 地图是一个简单的,但是这个非常有用的例子。 它需要为自变量的函数(可以称之为f )和一个列表lf必须采取一个参数的函数,而只是地图应用f到列表中的每一个元素lf可以做任何你需要做的每一个元素:添加一个到每个元素,方形的每一个元素,每个元素写入数据库,或打开Web浏览器窗口的每一个元素,这恰好是一个有效的URL。

使用的优点map在于它很好地概括遍历列表中的元素。 所有你需要做的是说“做f每一个元素,它是由map来决定如何最好地做到这一点。例如map可以实现对多个线程之间分割的工作,这将是完全透明的呼叫者,召集者。

请注意, map是不特定在所有的Perl。 它是由功能语言中使用的标准技术。 它甚至可以被用C使用函数指针使用“功能对象”来实现,或在C ++中。



Answer 9:

“只要糖”是苛刻。 请记住,一个循环就是糖 - 如果公司和转到可以做任何事情的循环结构做多。

地图是一个足够高的水平的功能,它可以帮助你在你的脑袋抱多大的更复杂的操作,这样你就可以编写和调试更大的问题。



Answer 10:

要通过霍尔与施瓦茨意译“有效Perl编程”,地图可能会被滥用,但我认为这是最适合用来创建现有列表的新列表。

创建的3,2平方的名单,与1:

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


Answer 11:

生成密码:

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


Answer 12:

您可以使用地图转换列表,并且将结果赋给另一个列表,grep来筛选列表并分配的结果,另一份清单。 “其他”列表可以是相同的变量,您要变换/过滤列表。

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


Answer 13:

它使用任何时候你想从现有的列表中创建一个新的列表。

举例来说,你可以字符串列表上映射解析功能将它们转换为整数。



Answer 14:

它可以让你变身列表作为一个表达式 ,而不是语句 。 想象一下,像这样定义士兵的哈希:

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

那么你就可以名之列分开操作。

例如,

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

是一个表达式 。 它可以去任何允许使用表达式 - 除了你不能分配给它。

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

索引数组,取最大值。

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

我发现的运算式的优点之一是它减少了对来自临时变量的错误。

如果麦考伊先生要过滤掉所有哈特的考虑,您可以添加用最少的代码查收。

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

我可以继续链接这些表达,这样,如果我与这​​个数据交互必须达到深为特定的目的,我没有写很多代码,假装我会做更多的事情。



Answer 15:

正如其他人所说,从地图列表创建列表。 认为“映射”一个列表的内容到另一个的。 下面是一个CGI程序的一些代码采取的专利号和打印超链接到专利申请的列表:

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


Answer 16:

正如其他人所说,地图是一种转换列表中最有用的。 什么也没有被提及是地图和一个“对等”循环之间的差别。

一个区别是,不会为修改它遍历列表中的表达式工作。 其中一个终止的,和其他没有:

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

另一个小的区别是,地图块内的上下文是列表环境,但对于循环赋予无效的情况下。



文章来源: What's the point of Perl's map?
标签: perl list map