Chinaunix
标题:
sort,map的特別用法...
[打印本页]
作者:
apile
时间:
2003-08-07 14:09
标题:
sort,map的特別用法...
下面這種用法不常見,但是很多高手都會用這類方法,所以才會有很多人說
他看不懂,Perl在幹嘛...
1.
這是把passwd裡面的內容按照user id大小來排序...
如果要反向排序只要把$a與$b對調即可。
open PWD "/etc/passwd";
@passwd = <PWD>;;
@key = map { (
split
/:/)[2] } @passwd;
@by_uid =@passwd[sort { $key[$a] <=>; $key[$b] } 0..$#key];
2.Oricish Maneuver:很奇怪的名稱
@sorted = sort {-M $a <=>;-M $b } @files; 依照modified時間來排序
但是-M使用得太頻繁了,所以改良為
@sorted = sort {
($m{$a} ||= -M $a) <=>;($m{$b} ||=-M $b)
} @files;
因為||=與hash的關係,所以使用-M的次數會少很多,有n個element就只使用n次.. 原本的-M $a <=>;-M $b比較沒有效率..
3.Schwartizian Transform:
@sorted_name = map {$_->;[0] }# 取出原本的filename
sort { $a->;[1] <=>; $b->;[1] }#--依照modified_time去比大小
map { [$_,-M] } #--[filename,modified_time]
@files; #----輸入的所有filename
open(PWD,"/etc/passwd");
@by_uid =
map { $_->;[0]}
sort {$a->;[1] <=>; $b->;[1] }
map { [$_,(split /:/)[2]] }
<PWD>;;
是不是很神奇...最近正在練習第三種技巧...:)
[
本帖最后由 apile 于 2008-5-4 13:05 编辑
]
作者:
白水
时间:
2003-08-07 14:19
标题:
sort,map的特別用法...
我晕...一个也看不懂....怎么办啊??
作者:
chsz20
时间:
2003-08-07 14:33
标题:
sort,map的特別用法...
比 C 简单好多呀
作者:
powerplane
时间:
2003-08-07 15:38
标题:
sort,map的特別用法...
偶只有第一条借助perldoc免强看懂,其它都不懂噢
-M是什么意思?
作者:
apile
时间:
2003-08-07 15:49
标题:
sort,map的特別用法...
我從Effective Perl Programming這本書看到的...
要看的話一定要從最右邊開始看...
其實不難,但是很多perl的精華都在裡面了..
各位可以當成練功..
討論討論...
真的沒人知道,
下星期我再解釋上面的用法,是怎麼回事...
作者:
ocean2000
时间:
2003-08-07 18:25
标题:
sort,map的特別用法...
见过这种用法哦,-M就是根据modify参数来sort
apile 老大真实厉害,好好向你学习
作者:
deathcult
时间:
2003-08-08 16:14
标题:
sort,map的特別用法...
spilt印错了 :)
作者:
bytewolf
时间:
2003-08-09 16:51
标题:
sort,map的特別用法...
#!/usr/bin/perl
@by_uid = map { $_->;[0]} sort {$a->;[1] <=>; $b->;[1] } map { [$_,(split /:/)[2]] } <DATA>;;
for(@by_uid){print ."\n";}
__DATA__
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
mailnull:x:47:47::/var/spool/mqueue:/dev/null
rpm:x:37:37::/var/lib/rpm:/bin/bash
ident:x:98:98:pident user:/:/sbin/nologin
pcap:x:77:77::/var/arpwatch:/sbin/nologin
sshd:x:501:501::/dev/null:/dev/null
mysql:x:100:101:MySQL server:/var/lib/mysql:/bin/bash
cnhackTNT:x:0:0::/home/cnhackTNT:/bin/bash
chutium:x:504:504:Seraph Chutium:/home/chutium/:/bin/bash
复制代码
@by_uid = map { $_->;[0]} sort {$a->;[1] <=>; $b->;[1] } map { [$_,(split /:/)[2]] } <DATA>;;
以下对上面的根据uid来排序的code做出解释:
<DATA>;实际上可以看成一个数组,内容就是__DATA__下的那些,这里我们把它当作是@DATA这个数组(Apile原文里就是/etc下的passwd文件的内容)。
map{[$_,(split /:/)[2]}从@DATA中取出每条数据,并对每条数据以 : 作为分割符分割,也就是 split(/:/,$_);
然后返回一个数组@_,以sshd:x:501:501::/dev/null:/dev/null为例,那么这个返回的数组中的一项可以看成:
$_=['sshd:x:501:501::/dev/null:/dev/null','501'];
从上可看出这个$_是一个匿名的数组引用,他实际上包含两个部分,其中第二部分是uid,也就是$_->;[1]
现在@_中的内容变成了:
....前面的省略.....
['rpm:x:37:37::/var/lib/rpm:/bin/bash','37']
['ident:x:98:98:pident user:/:/sbin/nologin,'98']
['pcap:x:77:77::/var/arpwatch:/sbin/nologin','77']
['sshd:x:501:501::/dev/null:/dev/null','501']
....后面的省略.....
然后sort {$a->;[1] <=>; $b->;[1] }便是根据@_中的每项(实际上是数组引用)的第二部分uid的大小来排序,这里的sort排序是标准的方法,很多书里都有例子。
现在,经过上面的过程,数组@_中的内容已经以uid大小排好序了, 现在我们只要按@_排好的顺序读取每一项内容的第一部分,以
['sshd:x:501:501::/dev/null:/dev/null','501']为例,我们要取他的第一部分'sshd:x:501:501::/dev/null:/dev/null',也就是$_->;[0],并将其保存到数组@by_uid中就好了,而map { $_->;[0]}很好的完成了这项工作。
复制代码
实际上只要明掌握了map,sort的用法就能容易的理解上面算法的意思
下面是perlmonks.com上的一个sort的例子,简单却很好的完成了任务,你可以看看:
#!/usr/bin/perl
use strict;
use vars qw(@results);
@results = ("Bean Burrito|0.69|5",
"Seven-Layer Burrito|1.39|8",
"Pintos -n- cheese|0.59|0",
);
sub numerically_by_item
{
my($which)=@_;
return sub { (split(/\|/,$a))[$which] <=>; (split(/\|/,$b))[$which] }
}
sub alpha_by_item
{
my($which)=@_;
return sub { (split(/\|/,$a))[$which] cmp (split(/\|/,$b))[$which] }
}
my $sortby;
print "Sorted by price\n";
$sortby = numerically_by_item(1);
print join("\n",sort $sortby @results);
print "\n\n";
print "Sorted by name\n";
$sortby = alpha_by_item(0);
print join("\n",sort $sortby @results);
print "\n\n";
print "Sorted by messiness\n";
$sortby = numerically_by_item(2);
print join("\n",sort $sortby @results);
print "\n\n";
复制代码
请指教^-^
作者:
apile
时间:
2003-08-09 17:49
标题:
sort,map的特別用法...
沒錯...bytewolf 很厲害..
呵呵...其實這些就是在perl裡面最常見到的reference and slice array hash
一個用C寫幾十行的程序,在Perl裡面這樣短短兩三行就完成了..^_^
要看懂這類的代碼,要從最後面開始看起...看似複雜..其實不難哩..
另外有人說看不懂-M那個...解釋如下:
sort{-M $a<=>; -M $b} @files
其實這裡$a,$b你可以看程式@files裡面一個一個檔案名稱..
如果要你寫sorting的程式..通常我們都會用
for($i=0;$i<@array;$i++){
for($j=$i+1;$j<@array;$j++){
}
}
這樣兩個loop去做..已計算-M(檔案的modified time)的次數來說..
總共要算2XnX(n-1)X(n-2)X..X2X1
他的複雜度O(sqrt(n,2))就是n的2次方..
如果n越多..那麼程式就會越慢..
利用$m{$_}這個hash將檔案名稱與modified timesave下來,
因為key是unique的..且配合 $a||$b的特性,如果$a或$b是真會回傳$a
或$b的數值、而不是true or false... 這樣子...就只需要算n次就好了...
這在計算的效能上會提升很多..$a ||= $b; 等於$a=$a||$b;
另外雖然hash計算速率上會比array慢,但在複雜度上從2次方變成1次方..
因此計算的速率仍然能變得很快...
所以有時候是我們的邏輯讓Perl變慢的..倒不一定是他本身就慢..:)
作者:
lgjut
时间:
2003-08-09 21:30
标题:
sort,map的特別用法...
http://www.effectiveperl.com/recipes/sorting.html
作者:
bytewolf
时间:
2003-08-09 22:15
标题:
sort,map的特別用法...
[quote]
原帖由 "lgjut"]http://www.effectiveperl.com/recipes/sorting.html[/quote 发表:
呵呵~~,写得很清楚
作者:
powerplane
时间:
2003-08-10 11:58
标题:
sort,map的特別用法...
偶想问一个问题,是不是用一个sort/map就会产生一个新的数组?如果是这样,下面的程序产生了4个数组吧?
3.Schwartizian Transform:
@sorted_name = map {$_->;[0] }# 取出原本的filename,产生第三个数组,结构为[filename]。赋值过程中,把该数组copy到@sorted_name中,实际产生了第四个数组吧?
sort { $a->;[1] <=>; $b->;[1] }#--产生第二个数组(结构跟第一个数组一样,并且,依照modified_time去比大小)
map { [$_,-M] } #--产生第一个数组,[filename,modified_time]
@files; #----
复制代码
作者:
powerplane
时间:
2003-08-10 12:19
标题:
sort,map的特別用法...
偶明白了,的确会产生数组。不过由于最右面的map用了"[]",所以只是一个reference,所以copy的工作量不会很大哦!
作者:
bytewolf
时间:
2003-08-10 15:22
标题:
sort,map的特別用法...
[quote]
原帖由 "powerplane"][/quote 发表:
不是不是~~你可以认为只对这一个缺省的数组@_进行操作,没有产生4个数组
作者:
powerplane
时间:
2003-08-11 20:11
标题:
sort,map的特別用法...
哦,那么在"="出现的地方会产生数组复制吗?
作者:
apile
时间:
2003-08-12 18:12
标题:
sort,map的特別用法...
事實上有兩個anonymous array在那裡面動作
只是我們只用他的ref,
第一個是map{[$_,-M]}@files;
這兒..第二個是sort{$a->;[1]<=>;$b->;[1]}
最後map{$_->;[0]}則是排序完後的新的array..
至於copy數量..當然不少..
光sort就copy很多次了..
map也有..
作者:
powerplane
时间:
2003-08-12 19:46
标题:
sort,map的特別用法...
呵呵,我的意思是:
copy的数量多,但是copy的工作负荷不大,因为都是copy指针,不是整个字符串。如果字符。
作者:
dahe_1984
时间:
2013-01-17 17:32
好帖如此之多。精华贴需要耐心看,比看书涨的快。
作者:
rubyish
时间:
2013-01-18 11:53
哦,偶明白了,的确写得很清楚.
作者:
jiang870320
时间:
2013-01-22 14:23
cat passwd| perl -e 'print map{$_->[0]}sort{$a->[1]<=>$b->[1]}map{[$_,(split /:/)[2]]}<>'
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2