免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 13919 | 回复: 12
打印 上一主题 下一主题

【Perl 文档中文化计划】Perl 二维数组教程翻译完成。 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-09 15:28 |只看该作者 |倒序浏览
非常简短的一个二维数组教程,由鄙人翻译完成。

最新版本可以从这里获取(POD 格式):
http://svn.perlchina.org/trunk/POD2-CN/lib/POD2/CN/perllol.pod

  1. NAME
  2.     perllol - 操作数组的数组(二维数组)

  3. 说明
  4.   声明和访问数组的数组
  5.     创建一个数组的数组(有时也可以叫“列表的列表”,不过不太准确)真是再简
  6.     单也不过了。它相当容易理解,并且本文中出现的每个例子都有可能在实际应用
  7.     中出现。

  8.     数组的数组就是一个普通的数组(@AoA),不过可以接受两个下标("$AoA[3][2])。
  9.     下面先定义一个这样的数组: "

  10.         # 一个包含有“指向数组的引用”的数组
  11.         @AoA = (
  12.             [ "fred", "barney" ],
  13.             [ "george", "jane", "elroy" ],
  14.             [ "homer", "marge", "bart" ],
  15.         );

  16.         print $AoA[2][2];
  17.       bart

  18.     你可能已经注意到,外面的括号是圆括号,这是因为我们想要给数组赋值,所以
  19.     需要圆括号。如果你*不*希望这里是 @AoA,而是一个指向它的引用,那么就得
  20.     这样:

  21.         # 一个指向“包含有数组引用的数组”的引用
  22.         $ref_to_AoA = [
  23.             [ "fred", "barney", "pebbles", "bambam", "dino", ],
  24.             [ "homer", "bart", "marge", "maggie", ],
  25.             [ "george", "jane", "elroy", "judy", ],
  26.         ];

  27.         print $ref_to_AoA->[2][2];

  28.     注意外面的括号现在变成了方括号,并且我们的访问语法也有所改变。这时因为
  29.     和 C 不同,在 Perl 中你不能自由地交换数组和引用(在 C 中,数组和指针在
  30.     很多地方可以互相代替使用)。$ref_to_AoA 是一个数组引用,而 @AoA 是一个
  31.     数组。同样地,$AoA[2] 也不是一个数组,而是一个数组引用。所以下面这
  32.     两行:

  33.         $AoA[2][2]
  34.         $ref_to_AoA->[2][2]

  35.     也可以用这两行来代替:

  36.         $AoA[2]->[2]
  37.         $ref_to_AoA->[2]->[2]

  38.     这是因为这里有两个相邻的括号(不管是方括号还是花括号),所以你可以随意
  39.     地省略箭头符号。但是如果 $ref_to_AoA 后面的那个箭头不能省略,因为省略
  40.     了就没法知道 $ref_to_AoA 到底是引用还是数组了 ^_^。

  41.   修改二维数组
  42.     前面的例子里我们创建了包含有固定数据的二维数组,但是如何往其中添加新元
  43.     素呢?再或者如何从零开始创建一个二维数组呢?

  44.     首先,让我们试着从一个文件中读取二维数组。首先我们演示如何一次性添加一
  45.     行。首先我们假设有这样一个文本文件:每一行代表了二维数组的行,而每一个
  46.     单词代表了二维数组的一个元素。下面的代码可以把它们储存到 @AoA:

  47.         while (<>) {
  48.             @tmp = split;
  49.             push @AoA, [ @tmp ];
  50.         }

  51.     你也可以用一个函数来一次读取一行:

  52.         for $i ( 1 .. 10 ) {
  53.             $AoA[$i] = [ somefunc($i) ];
  54.         }

  55.     或者也可以用一个临时变量来中转一下,这样看起来更清楚些:

  56.         for $i ( 1 .. 10 ) {
  57.             @tmp = somefunc($i);
  58.             $AoA[$i] = [ @tmp ];
  59.         }

  60.     注意方括号 "[]" 在这里非常重要。方括号实际上是数组引用的构造器。如果不
  61.     用方括号而直接写,那就犯了很严重的错误:

  62.         $AoA[$i] = @tmp;

  63.     你看,把一个数组赋值给了一个标量,那么其结果只是计算了 @tmp 数组的元素个
  64.     数,我想这肯定不是你希望的。

  65.     如果你打开了 "use strict",那么你就得先定义一些变量然后才能避免警告:

  66.         use strict;
  67.         my(@AoA, @tmp);
  68.         while (<>) {
  69.             @tmp = split;
  70.             push @AoA, [ @tmp ];
  71.         }

  72.     当然,你也可以不要临时变量:

  73.         while (<>) {
  74.             push @AoA, [ split ];
  75.         }

  76.     如果你知道想要放在什么地方的话,你也可以不要 push(),而是直接进行赋值:

  77.         my (@AoA, $i, $line);
  78.         for $i ( 0 .. 10 ) {
  79.             $line = <>;
  80.             $AoA[$i] = [ split ' ', $line ];
  81.         }

  82.     甚至是这样:

  83.         my (@AoA, $i);
  84.         for $i ( 0 .. 10 ) {
  85.             $AoA[$i] = [ split ' ', <> ];
  86.         }

  87.     你可能生怕 <> 在列表上下文会出差错,所以想要明确地声明要在标量上下文中
  88.     对 <> 求值,这样可读性会更好一些: (译者注:列表上下文中,<>
  89.     返回所有的行,标量上下文中 <> 只返回一行。)

  90.         my (@AoA, $i);
  91.         for $i ( 0 .. 10 ) {
  92.             $AoA[$i] = [ split ' ', scalar(<>) ];
  93.         }

  94.     如果你想用 $ref_to_AoA 这样的一个引用来代替数组,那你就得这么写:

  95.         while (<>) {
  96.             push @$ref_to_AoA, [ split ];
  97.         }

  98.     现在你已经知道如何添加新行了。那么如何添加新列呢?如果你正在做数学中的
  99.     矩阵运算,那么要完成类似的任务:

  100.         for $x (1 .. 10) {
  101.             for $y (1 .. 10) {
  102.                 $AoA[$x][$y] = func($x, $y);
  103.             }
  104.         }

  105.         for $x ( 3, 7, 9 ) {
  106.             $AoA[$x][20] += func2($x);
  107.         }

  108.     想要访问的某个元素是不是存在是无关紧要的:因为如果不存在那么 Perl 会给
  109.     你自动创建!新创建的元素的值是 "undef"。

  110.     如果你想添加到一行的末尾,你可以这么做:

  111.         # 添加新列到已存在的行
  112.         push @{ $AoA[0] }, "wilma", "betty";

  113.     注意我*没有*这么写:

  114.         push $AoA[0], "wilma", "betty";  # 错误!

  115.     事实上,上面这句根本就没法通过编译!为什么?因为 push() 的第一个参数必
  116.     须是一个真实的数组,不能是引用。

  117.   访问和打印
  118.     现在是打印二维数组的时候了。那么怎么打印?很简单,如果你只想打印一个元
  119.     素,那么就这么来一下:

  120.         print $AoA[0][0];

  121.     如果你想打印整个数组,那你可不能这样:

  122.         print @AoA;         # 错误!

  123.     因为你这么做只能得到一列引用,Perl 从来都不会自动地为你解引用。作为替
  124.     代,你必须得弄个循环或者是双重循环。用 shell 风格的 for() 语句就可以
  125.     打印整个二维数组:

  126.         for $aref ( @AoA ) {
  127.             print "\t [ @$aref ],\n";
  128.         }

  129.     如果你要用下标来遍历的话,你得这么做:

  130.         for $i ( 0 .. $#AoA ) {
  131.             print "\t elt $i is [ @{$AoA[$i]} ],\n";
  132.         }

  133.     或者这样用双重循环(注意内循环):

  134.         for $i ( 0 .. $#AoA ) {
  135.             for $j ( 0 .. $#{$AoA[$i]} ) {
  136.                 print "elt $i $j is $AoA[$i][$j]\n";
  137.             }
  138.         }

  139.     如同你看到的一样,它有点儿复杂。这就是为什么有时候用临时变量能够看起来
  140.     更简单一些的原因:

  141.         for $i ( 0 .. $#AoA ) {
  142.             $aref = $AoA[$i];
  143.             for $j ( 0 .. $#{$aref} ) {
  144.                 print "elt $i $j is $AoA[$i][$j]\n";
  145.             }
  146.         }

  147.     哦,好像还有点复杂,那么试试这样:

  148.         for $i ( 0 .. $#AoA ) {
  149.             $aref = $AoA[$i];
  150.             $n = @$aref - 1;
  151.             for $j ( 0 .. $n ) {
  152.                 print "elt $i $j is $AoA[$i][$j]\n";
  153.             }
  154.         }

  155.   切片
  156.     切片是指数组的一部分。如果你想要得到多维数组的一个切片,那你得进行一些
  157.     下标运算。通过箭头可以方便地为单个元素解引用,但是访问切片就没有这么好
  158.     的事了。当然,我们可以通过循环来取切片。

  159.     我们先演示如何用循环来获取切片。我们假设 @AoA 变量的值和前面一样。

  160.         @part = ();
  161.         $x = 4;
  162.         for ($y = 7; $y < 13; $y++) {
  163.             push @part, $AoA[$x][$y];
  164.         }

  165.     这个循环其实可以用一个切片操作来代替:

  166.         @part = @{ $AoA[4] } [ 7..12 ];

  167.     不过这个看上去似乎略微有些复杂。

  168.     下面再教你如何才能得到一个 *二维切片*, 比如 $x 从 4 到 8,$y 从 7 到
  169.     12,应该怎么写?

  170.         @newAoA = ();
  171.         for ($startx = $x = 4; $x <= 8; $x++) {
  172.             for ($starty = $y = 7; $y <= 12; $y++) {
  173.                 $newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
  174.             }
  175.         }

  176.     也可以省略掉中间的那层循环:

  177.         for ($x = 4; $x <= 8; $x++) {
  178.             push @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ];
  179.         }

  180.     其实用 map 函数可以更加简练:

  181.         @newAoA = map { [ @{ $AoA[$_] } [ 7..12 ] ] } 4 .. 8;

  182.     虽然你的经理也许会抱怨这种难以理解的代码可能会带来安全隐患,
  183.     然而这种观点还是颇有争议的(兴许还可以更加安全也说不定 ^_^)。
  184.     换了是我,我会把它们放进一个函数中实现:

  185.         @newAoA = splice_2D( \@AoA, 4 => 8, 7 => 12 );
  186.         sub splice_2D {
  187.             my $lrr = shift;        # 指向二维数组的引用
  188.             my ($x_lo, $x_hi,
  189.                 $y_lo, $y_hi) = @_;

  190.             return map {
  191.                 [ @{ $lrr->[$_] } [ $y_lo .. $y_hi ] ]
  192.             } $x_lo .. $x_hi;
  193.         }

  194. 参见
  195.     perldata(1), perlref(1), perldsc(1)

  196. 作者
  197.     Tom Christiansen <tchrist@perl.com>

  198.     Last update: Thu Jun 4 16:16:23 MDT 1998

  199. 翻译者及翻译声明
  200.     本文由 flw ("flw@cpan.org") 翻译,翻译成果首次出现在 *中国 Perl 协会*
  201.     http://www.perlchina.org) 的协作开发平台上。

  202.     PerlChina.org 本着“在国内推广 Perl” 的目的,组织人员翻译本文。读者可
  203.     以在遵守原作者许可协议、尊重原作者及译作者劳动成果的前提下,任意发布或
  204.     修改本文。

  205.     本文作者用一种轻松地口吻简要介绍了一下二维数组的用法,但是正因如此,文
  206.     中有些内容直译过来反而很拗口、很难懂(毕竟中西方文化不同嘛),因此译者
  207.     在翻译时,对原文有较多的修改。喜欢阅读英文原版胜过喜欢翻译版的朋友们,
  208.     可以直接看原版 ^_^,同时也希望能够理解译者的一篇苦心,而不要在背后骂我
  209.     翻译得不对就是了。

  210.     希望本文能对英文不好的朋友们有所帮助。

  211.     如果你对本文有任何意见,欢迎来信指教。本人非常欢迎与各位交流。
复制代码

论坛徽章:
0
2 [报告]
发表于 2006-06-09 16:18 |只看该作者
辛苦了,你先休息休息,抽带烟吧

论坛徽章:
0
3 [报告]
发表于 2006-07-26 13:49 |只看该作者
我顶  很用力的顶

论坛徽章:
0
4 [报告]
发表于 2006-07-27 09:19 |只看该作者
非常感谢

论坛徽章:
0
5 [报告]
发表于 2008-10-21 14:40 |只看该作者
谢谢~
努力学习中。。。

论坛徽章:
0
6 [报告]
发表于 2008-10-21 15:31 |只看该作者
svn 连接时报错:Server sent unexpected return value (405 Method Not Allowed) in response to
怎么回事啊

论坛徽章:
0
7 [报告]
发表于 2008-11-18 20:17 |只看该作者
好文,谢谢!

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
8 [报告]
发表于 2008-11-19 13:06 |只看该作者
顶一下,flw老大辛苦了

论坛徽章:
1
未羊
日期:2014-09-08 22:47:27
9 [报告]
发表于 2008-11-20 16:07 |只看该作者
这个文章看了很受启发,我已经在自己用的脚本里使用了,谢谢楼主。

论坛徽章:
0
10 [报告]
发表于 2009-05-05 03:40 |只看该作者
多谢楼主,正在琢磨二维数组呢,顶起来!:wink:
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP