免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 16336 | 回复: 19

sort,map的特別用法... [复制链接]

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
发表于 2003-08-07 14:09 |显示全部楼层
下面這種用法不常見,但是很多高手都會用這類方法,所以才會有很多人說
他看不懂,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 编辑 ]

论坛徽章:
0
发表于 2003-08-07 14:19 |显示全部楼层

sort,map的特別用法...

我晕...一个也看不懂....怎么办啊??

论坛徽章:
0
发表于 2003-08-07 14:33 |显示全部楼层

sort,map的特別用法...

比 C 简单好多呀

论坛徽章:
0
发表于 2003-08-07 15:38 |显示全部楼层

sort,map的特別用法...

偶只有第一条借助perldoc免强看懂,其它都不懂噢
-M是什么意思?

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
发表于 2003-08-07 15:49 |显示全部楼层

sort,map的特別用法...

我從Effective Perl Programming這本書看到的...
要看的話一定要從最右邊開始看...
其實不難,但是很多perl的精華都在裡面了..

各位可以當成練功..
討論討論...
真的沒人知道,
  
下星期我再解釋上面的用法,是怎麼回事...

论坛徽章:
0
发表于 2003-08-07 18:25 |显示全部楼层

sort,map的特別用法...

见过这种用法哦,-M就是根据modify参数来sort

apile 老大真实厉害,好好向你学习

论坛徽章:
0
发表于 2003-08-08 16:14 |显示全部楼层

sort,map的特別用法...

spilt印错了 :)

论坛徽章:
0
发表于 2003-08-09 16:51 |显示全部楼层

sort,map的特別用法...


  1. #!/usr/bin/perl

  2. @by_uid = map { $_->;[0]} sort {$a->;[1] <=>; $b->;[1] } map { [$_,(split /:/)[2]] } <DATA>;;
  3. for(@by_uid){print ."\n";}

  4. __DATA__
  5. root:x:0:0:root:/root:/bin/bash
  6. bin:x:1:1:bin:/bin:/sbin/nologin
  7. daemon:x:2:2:daemon:/sbin:/sbin/nologin
  8. adm:x:3:4:adm:/var/adm:/sbin/nologin
  9. sync:x:5:0:sync:/sbin:/bin/sync
  10. shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
  11. halt:x:7:0:halt:/sbin:/sbin/halt
  12. mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
  13. ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
  14. nobody:x:99:99:Nobody:/:/sbin/nologin
  15. mailnull:x:47:47::/var/spool/mqueue:/dev/null
  16. rpm:x:37:37::/var/lib/rpm:/bin/bash
  17. ident:x:98:98:pident user:/:/sbin/nologin
  18. pcap:x:77:77::/var/arpwatch:/sbin/nologin
  19. sshd:x:501:501::/dev/null:/dev/null
  20. mysql:x:100:101:MySQL server:/var/lib/mysql:/bin/bash
  21. cnhackTNT:x:0:0::/home/cnhackTNT:/bin/bash
  22. chutium:x:504:504:Seraph Chutium:/home/chutium/:/bin/bash

复制代码


  1. @by_uid = map { $_->;[0]} sort {$a->;[1] <=>; $b->;[1] } map { [$_,(split /:/)[2]] } <DATA>;;

  2. 以下对上面的根据uid来排序的code做出解释:

  3. <DATA>;实际上可以看成一个数组,内容就是__DATA__下的那些,这里我们把它当作是@DATA这个数组(Apile原文里就是/etc下的passwd文件的内容)。

  4. map{[$_,(split /:/)[2]}从@DATA中取出每条数据,并对每条数据以 : 作为分割符分割,也就是 split(/:/,$_);

  5. 然后返回一个数组@_,以sshd:x:501:501::/dev/null:/dev/null为例,那么这个返回的数组中的一项可以看成:
  6. $_=['sshd:x:501:501::/dev/null:/dev/null','501'];
  7. 从上可看出这个$_是一个匿名的数组引用,他实际上包含两个部分,其中第二部分是uid,也就是$_->;[1]
  8. 现在@_中的内容变成了:

  9. ....前面的省略.....
  10. ['rpm:x:37:37::/var/lib/rpm:/bin/bash','37']
  11. ['ident:x:98:98:pident user:/:/sbin/nologin,'98']
  12. ['pcap:x:77:77::/var/arpwatch:/sbin/nologin','77']
  13. ['sshd:x:501:501::/dev/null:/dev/null','501']
  14. ....后面的省略.....


  15. 然后sort {$a->;[1] <=>; $b->;[1] }便是根据@_中的每项(实际上是数组引用)的第二部分uid的大小来排序,这里的sort排序是标准的方法,很多书里都有例子。
  16. 现在,经过上面的过程,数组@_中的内容已经以uid大小排好序了, 现在我们只要按@_排好的顺序读取每一项内容的第一部分,以
  17. ['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的例子,简单却很好的完成了任务,你可以看看:

  1. #!/usr/bin/perl

  2. use strict;

  3. use vars qw(@results);
  4. @results = ("Bean Burrito|0.69|5",
  5.             "Seven-Layer Burrito|1.39|8",
  6.             "Pintos -n- cheese|0.59|0",
  7. );

  8. sub numerically_by_item
  9. {
  10.   my($which)=@_;
  11.   return sub { (split(/\|/,$a))[$which] <=>; (split(/\|/,$b))[$which] }
  12. }

  13. sub alpha_by_item
  14. {
  15.   my($which)=@_;
  16.   return sub { (split(/\|/,$a))[$which] cmp (split(/\|/,$b))[$which] }
  17. }

  18. my $sortby;

  19. print "Sorted by price\n";
  20. $sortby = numerically_by_item(1);
  21. print join("\n",sort $sortby @results);
  22. print "\n\n";

  23. print "Sorted by name\n";
  24. $sortby = alpha_by_item(0);
  25. print join("\n",sort $sortby @results);
  26. print "\n\n";

  27. print "Sorted by messiness\n";
  28. $sortby = numerically_by_item(2);
  29. print join("\n",sort $sortby @results);
  30. print "\n\n";

复制代码


请指教^-^

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
发表于 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變慢的..倒不一定是他本身就慢..:)

论坛徽章:
0
发表于 2003-08-09 21:30 |显示全部楼层

sort,map的特別用法...

http://www.effectiveperl.com/recipes/sorting.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP