perl map-map用法示例和grep的用法

来源:互联网 发布:系统网络连接未准备好 编辑:程序博客网 时间:2024/05/21 20:25

1.转换文件名为文件大小

@sizes=map{-s$_}@file_names;

-s是个文件测试操作符,它返回某个文件的size。所以上面这句就返回@file_names数组里每个文件的大小,结果也是个数组。

2.转换数组到hash:找到某个数组值的索引

代替重复的搜索数组,我们可以用map来转换数组到hash,并通过hash关键字来进行直接查找。如下的map用法相对于重复的数组搜索,更简单高效。

@teams=qw(MiamiOregonFloridaTennesseeTexas
OklahomaNebraskaLSUColoradoMaryland);
%rank=map{$teams[$_],$_+1}0..$#teams;
print"Colorado:$rank{Colorado}/n";
print"Texas:$rank{Texas}(hook'em,Horns!)/n";

打印结果是:
Colorado:9
Texas:5(hook'em,Horns!)

上述code容易理解哦,0..$#teams是个列表,$#teams代表@teams最后一个元素的下标值(这里是9),所以这个列表就是0-9这几个数了。map遍历上述列表,将每个列表元素临时设置为$_,并对$_在中间的{}里进行计算;{$teams[$_],$_+1},这里每次计算后返回一个2元素的列表,列表结果是某个数组值和对应的数组下标加1,明白了呀?

由于对每个LIST元素进行计算时,都产生一个2元素的列表,所以总的map结果就可看作一个hash了。hash关键字就是数组元素,hash值是对应的数组下标加1。

3.转换数组到hash:查找拼错单词

转换数组到hash是map的最普遍用法。在本示例里,hash的值是无关紧要的,我们仅检查hash关键字是否存在。

%dictionary=map{$_,1}qw(catdogmanwomanhatglove);
@words=qw(dogkatwimenhatmangloove);
foreach$word(@words){
if(not$dictionary{$word}){
print"Possiblemisspelledword:$word/n";
}
}

打印结果是:
Possiblemisspelledword:kat
Possiblemisspelledword:wimen
Possiblemisspelledword:gloove

看看第1句的map用法,它跟前面示例里的差不多哦。qw()这里是个列表,map对这个列表里的每个元素进行{$_,1}计算,每次计算的结果返回一个2元素的列表,换句话说,就是%dictionary的key和value呀。所以map最终的结果就是一个hash了,关键字是qw()里的元素,值总是1,无关紧要的。

然后下面的foreach语句就容易了哦,如果@words里的元素不构成%dictionary的关键字的话,就打印一条出错消息。如果把%dictionary看成标准字典的话,那么就可用它来检验你自己的@words字库里是否有错字了呀。

4. 转换数组到hash:存储选中的CGI参数

hash通常是存储传递给程序或子函数的参数的最便利的方法,而map通常是创建这个hash的最便利的方法。

useCGIqw(param);
%params=map{$_,(param($_))[0]}
grep{lc($_)ne'submit'}param();

这里要了解一下CGI模块的基本知识。param()调用返回CGI参数名的列表;param($_)调用返回指定的CGI参数名的值。假如 param($_)返回某个CGI参数的多个值,那么(param($_))[0]只取第一个值,以便hash仍被良好定义。

上述 code的意思是,将param()的结果作为输入列表,它的元素是多个CGI参数名,然后从这些参数名里grep出参数名不等于'submit'的,结果是一个临时列表,map的{$_,(param($_))[0]}语句再次遍历这个临时列表,并获取到参数名,和对应的参数值,将结果赋给%params。所以%params里就存储了页面提交过来的,除了submit外的其他CGI参数名和参数值(只取第1个)。

很巧妙的用法,是不是?它结合用了map和grep,使code显得很简洁。

5.产生随机密码

@a=(0..9,'a'..'z');
$password=join'',map{$a[intrand@a]}0..7;
print"$password/n";

每次运行它会得到不同的结果,但长度总是8位,由0..7这个决定。如下是可能的输出:

y2ti3dal

它是个随机值,也许你能用它来做密码。

这里,需要先明白几个函数,rand产生一个随机值,它后面的@a其实是个标量哦,表示@a数组的长度,rand@a的结果可能是个小数,所以再用int函数来取整。intrand@a的结果是个整数,它>;=0但小于@a的长度。所以$a[intrand@a]就表示从@a数组里随机取出一个字符了。0..7表示总共取8次,返回的结果再用join连接起来,就构成一个8位随机密码了呀。

当然,(0..9,'a'..'z')数组元素太少了,你可以修改它,使其包含大小写字符,数字和标点符号,这样密码强度就高些。

6.从数组元素里剥离数字

不要在EXPR里修改LIST值。如下做法是不好的:

@digitless=map{tr/0-9//d;$_}@array;

它虽然从数组元素里剥离了数字,但同样破坏了该数组,:(

如下做法是good:

@digitless=map{($x=$_)=~tr/0-9//d;
$x;
}@array;

它将tr的结果赋给临时变量$x,并返回$x的值,这样就保护数组了呀。

7.打印"justanotherperlhacker"

printmap({chr}
('10611711511603209711011111610410111'.
'4032112101114108032104097099107101114')
=~/.../g
),"/n";

打印的结果是:
justanotherperlhacker

chr函数将单个数字转换到相应的ASCII字符。()=~/.../g语法以3个数字长度为单位,分割数字串到新的串列表。

比较无聊的用法,还不如用pack()和 unpack(),:P

8.转置矩阵

@matrix=([1,2,3],[4,5,6],[7,8,9]);
foreach$xyz(@matrix){
print"$xyz->;[0]$xyz->;[1]$xyz->;[2]/n";
}
@transposed=
map{$x=$_;
[map{$matrix[$_][$x]}0..$#matrix];
}0..$#{$matrix[0]};
print"/n";
foreach$xyz(@transposed){
print"$xyz->;[0]$xyz->;[1]$xyz->;[2]/n";

打印结果是:

123
456
789

147
258
369

这里稍微有点复杂哦,让我们分2步看看。

@matrix=([1,2,3],[4,5,6],[7,8,9]);
foreach$xyz(@matrix){
print"$xyz->;[0]$xyz->;[1]$xyz->;[2]/n";
}

这里不难明白,([1,2,3],[4,5,6],[7,8,9])是个数组,它的每个元素又是个匿名数组,这样在$xyz遍历数组时,$xyz->;[0],$xyz->;[1],$xyz->;[2]就可以访问到匿名数组里的元素了。所以会打印出:

123
456
789

@transposed=
map{$x=$_;
[map{$matrix[$_][$x]}0..$#matrix];
}0..$#{$matrix[0]};

这里复杂点,0..$#{$matrix[0]}是个列表,$#{$matrix[0]}表示$matrix[0]这个匿名数组的最大下标值,0..$#{$matrix[0]}表示矩阵的横向。$x=$_;这里将$_的值赋给$x,为什么呢?因为它后面又有个map嘛,$_的值会改变的,所以要先存储起来。外围的map返回的值是[]里的map计算出来的一个列表,以[]匿名数组形式返回。[]里面的map是这样的,它的输入LIST是 0..$#matrix,表示矩阵的纵向了。$matrix[$_][$x]这里先纵再横,就把矩阵值置换了一下。所以返回的结果列表 @transposed就包含置换后的矩阵了哦。

是否有点糊涂?那举例看看。这样看可能好点:

[1,2,3],
[4,5,6],
[7,8,9]

外围的map遍历时,先是横向下标遍历,停留在横向0位。然后第二个map,就是纵向下标遍历了,它要遍历所有纵向下标,这样在横向0位,就先返回[1,4,7]的列表了,然后在横向1位,又返回[2,5,8]的列表,最后在横向2位,返回[3,6,9]的列表。

9. 查找质数:警示用法

foreach$num(1..1000){
@expr=map{'$_%'.$_.'&&'}2..intsqrt$num;
if(eval"grep{@expr1}$num"){print"$num"}
}

打印结果是:
12357111317192329313741434753596167...

该code能工作,但它如此麻烦,违背了程序最基本的明晰法则。用如下直观的code代替它就可以了呀:

CANDIDATE:foreach$num(1..1000){
foreach$factor(2..intsqrt$num){
unless($num%$factor){nextCANDIDATE}
}
print"$num";

 

#!/usr/bin/perl
use warnings;
use strict;

my @list;
my @number;

open(INFILE, "/home/liuguiyou/alignment_2.txt");
open(OUTFILE, ">/home/liuguiyou/query.txt") ||   die "Cannot open the newfile: $!/n";

while(<INFILE>){
chomp;
@list=split;
@number=grep(/Query/, @list);

print OUTFILE "@number/n"; # or print OUTFILE "$_/n";
               }
exit;





output:
Query=SNP1 Query:
Query=SNP2 Query:
Query=SNP3 Query:
Query=SNP4 Query:
Query=SNP5 Query:
Query=SNP6 Query:
Query=SNP7 Query:
Query=SNP8 Query:
Query=SNP9 Query:
Query=SNP10 Query:

or print OUTFILE "$_/n"; output:
Query=SNP1  Query: 1     aattttggtggcagagatgg-tagtggttgctcagaaaacca 41
Query=SNP2  Query: 1     aaaaagaaacagaaatggttgtactagtgagaaagaagaaa 41
Query=SNP3  Query: 1     cacctactcccaccaccaaaaagcctccttctctttaccat 41
Query=SNP4  Query: 1     tttggcaattcttttacaagcccttggtcctgttttctcca 41
Query=SNP5  Query: 1      gaaaacgcatacgccatcctgattaaccaaacacacatatg 41
Query=SNP6  Query: 1      tatacaaaaaatttgatacatttttgataaacacattttga 41
Query=SNP7  Query: 1      tctgatttgaattccattttatcagactctcatccgtgcaa 41
Query=SNP8  Query: 1      gcgacactgagaagagacgatgagggaggtatgtgactata 41
Query=SNP9  Query: 1      aagatcacgaggcagagtttcgccacatgtccttcattgtt 41
Query=SNP10  Query: 1      gtggaaagatgatacagagtagagagatttcttcttcttct 41


map和grep都是列表处理函数,它们将一个列表转换成另一个列表。它们的语法如下:

map expression_r_r_r_r_r_r_r,LIST;
map BLOCK,LIST;
grep expression_r_r_r_r_r_r_r,LIST;
grep BLOCK,LIST;


map的目的是逐个转换列表中的元素,并产生一个新的列表作为结果,而grep是通过表达式或者程序块被计算为True或False值来返回原始列表的一个子集列表。

下面举例说明map的用法:
[liuguiyou@localhost ~]$ cat perl/map.pl
#!/usr/bin/perl -w
use strict;

my @numbers=(80,101,114,108);
my @list= map (chr,@numbers);
print @list;
print "/n";
;

  [liuguiyou@localhost ~]$ perl perl/map.pl
Perl


下面的用法也可以:
[root@test doc2sort]# cat map.pl

#!/usr/bin/perl -w
use strict;

my @numbers=(80,101,114,108);
print map {chr $_} @numbers;
print "/n";

[root@test doc2sort]# perl map.pl
Perl

当然我们也可以用foreach循环做同样的事,但map做的更简洁些。




grep的用法也是非常的简单:
[root@test doc2sort]# cat grep.pl

#!/usr/bin/perl -w
use strict;

my @list=(80,101,"hello","world",114,108);
my @number=grep {/^/d+/} @list;
print "@number/n";
[root@test doc2sort]# perl grep.pl
80 101 114 108


当然我们也可以用map来实现:
my @number=map {/^/d+/?$_:()} @list;
注意到()是不返回任何东西。

原创粉丝点击