linux社区爱心援助Linux认证系列教程业界动态站务新闻公司招聘建议留言网址大全LPI专题CISCO专题
设为首页
加入收藏
管理团队
JSP  
JAVA  
PERL  
 您的位置:首页 > 开发语言 > perl >
栏目导栏
  php
  JSP
  ASP
  asp.net
  JAVA
  c/c++/c#
  perl
  JavaScript
  Basic
  Delphi
资料搜索
热门文章
·perl入门学习指南
·perl入门教程:Perl 的变量
·Perl文件及目录操作
·perl入门教程:正则表达式
·perl入门教程:Perl的语法与C语
·perl入门教程:Perl概述
·Perl常用系统函数
·perl中传递和存储文件句柄
·perl 学习笔记
·perl入门教程:Perl 程序的属性
·Perl命令行应用介绍
·Perl连接Oracle数据库的方法
·curl+perl的自动MAIL报警程序
·Perl的基本输入输出
·使用 perldoc 找文档
最新文章
·perl 学习笔记
·Perl 特殊变量
·perl Base64码的获取
·perl 父子进程的数据库连接继承
·工作中的实用 perl 脚本
·perl中传递和存储文件句柄
·curl+perl的自动MAIL报警程序
·Perl类包的动态调用
·使用open创建的管道进行父子进
·perl 执行一个系统命令(svn in
·windows平台下根据可执行文件名
·关联数组(hash)
·Perl语言在风险评估的系统基础
·在Perl/CGI中使用模板
·PERL CGI 常见问题
Google
 
关联数组(hash)
[ 作者:  加入时间:2007-11-09 10:35:41  来自:Linux联盟收集整理 ]
数组元素通过数字下标访问,为了解决这类问题,Perl定义了另一种数组,可以用任意简单变量值来访问其元素,这种数组叫做关联数组,也叫哈希表。biLLinux联盟
    为了区分关联数组变量与普通的数组变量,Perl使用%作为其首字符,而数组变量以@打头。与其它变量名一样,%后的第一个字符必须为字母,后续字符可以为字母、数字或下划线。biLLinux联盟
三、访问关联数组的元素biLLinux联盟
    关联数组的下标可以为任何简单/标量值,访问单个元素时以$符号打头,下标用大括号围起来。例如:
$fruit{"bananas"}biLLinux联盟
$number{3.14159}biLLinux联盟
$integer{-7}
    简单变量也可作为下标,如:biLLinux联盟
    $fruit{$my_fruit}biLLinux联盟
四、增加元素biLLinux联盟
    创建一个关联数组元素最简单的方法是赋值,如语句$fruit{"bananas"} = 1; 把1赋给关联数组%fruit下标为bananas的元素,如果该元素不存在,则被创建,如果数组%fruit从未使用过,也被创建。biLLinux联盟
    这一特性使得关联数组很容易用于计数。下面我们用关联数组改写上面的程序,注意实现同样的功能此程序简化了许多。biLLinux联盟
1 : #!/usr/local/bin/perlbiLLinux联盟
2 :biLLinux联盟
3 : while ($inputline = ) {biLLinux联盟
4 :   while ($inputline =~ /\b[A-Z]\S+/g) {biLLinux联盟
5 :     $word = $&;biLLinux联盟
6 :     $word =~ s/[;.,:-]$//; # remove punctuationbiLLinux联盟
7 :     $wordlist{$word} += 1;biLLinux联盟
8 :   }biLLinux联盟
9 : }biLLinux联盟
10: print ("Capitalized words and number of occurrences:\n");biLLinux联盟
11: foreach $capword (keys(%wordlist)) {biLLinux联盟
12:   print ("$capword: $wordlist{$capword}\n");biLLinux联盟
13: }
    运行结果如下:biLLinux联盟
Here is a line of Input.biLLinux联盟
This Input contains some Capitalized words.biLLinux联盟
^DbiLLinux联盟
Capitalized words and number of occurrences:biLLinux联盟
This: 1biLLinux联盟
Input: 2biLLinux联盟
Here: 1biLLinux联盟
Capitalized: 1
    你可以看到,这次程序简单多了,读取输入并存贮各单词数目从20行减少到了7行。biLLinux联盟
    本程序用关联数组%wordlist跟踪首字母大写的单词,下标就用单词本身,元素值为该单词出现的次数。第11行使用了内嵌函数keys()。这个函数返回关联数组的下标列表,foreach语句就用此列表循环。biLLinux联盟
    注:关联数组总是随机存贮的,因此当你用keys()访问其所有元素时,不保证元素以任何顺序出现,特别值得一提的是,它们不会以被创建的顺序出现。biLLinux联盟
    要想控制关联数组元素出现的次序,可以用sort()函数对keys()返回值进行排列,如:
foreach $capword (sort keys(%wordlist)) {biLLinux联盟
  print ("$capword: $wordlist{$capword}\n");biLLinux联盟
}
五、创建关联数组biLLinux联盟
    可以用单个赋值语句创建关联数组,如:biLLinux联盟
    %fruit = ("apples",17,"bananas",9,"oranges","none");biLLinux联盟
    此语句创建的关联数组含有下面三个元素:
  • 下标为apples的元素,值为17
  • 下标为bananas的元素,值为9
  • 下标为oranges的元素,值为none
  •     注:用列表给关联数组赋值时,Perl5允许使用"=>"或","来分隔下标与值,用"=>"可读性更好些,上面语句等效于:biLLinux联盟
        %fruit = ("apples"=>17,"bananas"=>9,"oranges"=>"none");biLLinux联盟
    六、从数组变量复制到关联数组biLLinux联盟
        与列表一样,也可以通过数组变量创建关联数组,当然,其元素数目应该为偶数,如:biLLinux联盟
        @fruit = ("apples",17,"bananas",9,"oranges","none");biLLinux联盟
        %fruit = @fruit;biLLinux联盟
        反之,可以把关联数组赋给数组变量,如:biLLinux联盟
        %fruit = ("grapes",11,"lemons",27);biLLinux联盟
        @fruit = %fruit;biLLinux联盟
        注意,此语句中元素次序未定义,那么数组变量@fruit可能为("grapes",11,"lemons",27)或("lemons",27,"grapes",11)。biLLinux联盟
        关联数组变量之间可以直接赋值,如:%fruit2 = %fruit1; 还可以把数组变量同时赋给一些简单变量和一个关联数组变量,如:biLLinux联盟
        ($var1, $var2, %myarray) = @list;biLLinux联盟
        此语句把@list的第一个元素赋给$var1,第二个赋给$var2,其余的赋给%myarray。biLLinux联盟
        最后,关联数组可以通过返回值为列表的内嵌函数或用户定义的子程序来创建,下例中把split()函数的返回值--一个列表--赋给一个关联数组变量。
    1: #!/usr/local/bin/perlbiLLinux联盟
    2:biLLinux联盟
    3: $inputline = <STDIN>;biLLinux联盟
    4: $inputline =~ s/^\s+|\s+\n$//g;biLLinux联盟
    5: %fruit = split(/\s+/, $inputline);biLLinux联盟
    6: print ("Number of bananas: $fruit{\"bananas\"}\n");
        运行结果如下:
    oranges 5 apples 7 bananas 11 cherries 6biLLinux联盟
    Number of bananas: 11
    七、元素的增删biLLinux联盟
        增加元素已经讲过,可以通过给一个未出现过的元素赋值来向关联数组中增加新元素,如$fruit{"lime"} = 1;创建下标为lime、值为1的新元素。biLLinux联盟
        删除元素的方法是用内嵌函数delete,如欲删除上述元素,则:biLLinux联盟
        delete ($fruit{"lime"});biLLinux联盟
    注意:
    1、一定要使用delete函数来删除关联数组的元素,这是唯一的方法。biLLinux联盟
    2、一定不要对关联数组使用内嵌函数push、pop、shift及splice,因为其元素位置是随机的。
    八、列出数组的索引和值biLLinux联盟
        上面已经提到,keys()函数返回关联数组下标的列表,如:biLLinux联盟
    %fruit = ("apples", 9,biLLinux联盟
    "bananas", 23,biLLinux联盟
    "cherries", 11);biLLinux联盟
    @fruitsubs = keys(%fruits);biLLinux联盟
        这里,@fruitsubs被赋给apples、bananas、cherries构成的列表,再次提请注意,此列表没有次序,若想按字母顺序排列,可使用sort()函数。biLLinux联盟
        @fruitindexes = sort keys(%fruits);biLLinux联盟
        这样结果为("apples","bananas","cherries")。类似的,内嵌函数values()返回关联数组值的列表,如:biLLinux联盟
    %fruit = ("apples", 9,biLLinux联盟
    "bananas", 23,biLLinux联盟
    "cherries", 11);biLLinux联盟
    @fruitvalues = values(%fruits);biLLinux联盟
        这里,@fruitvalues可能的结果为(9,23.11),次序可能不同。biLLinux联盟
    九、用关联数组循环biLLinux联盟
        前面已经出现过利用keys()函数的foreach循环语句,这种循环效率比较低,因为每返回一个下标,还得再去寻找其值,如:biLLinux联盟
    foreach $holder (keys(%records)){biLLinux联盟
      $record = $records{$holder};biLLinux联盟
    }
        Perl提供一种更有效的循环方式,使用内嵌函数each(),如:biLLinux联盟
    %records = ("Maris", 61, "Aaron", 755, "Young", 511);biLLinux联盟
    while (($holder, $record) = each(%records)) {biLLinux联盟
      # stuff goes herebiLLinux联盟
    }
        each()函数每次返回一个双元素的列表,其第一个元素为下标,第二个元素为相应的值,最后返回一个空列表。biLLinux联盟
        注意:千万不要在each()循环中添加或删除元素,否则会产生不可预料的后果。biLLinux联盟
    十、用关联数组创建数据结构biLLinux联盟
        用关联数组可以模拟在其它高级语言中常见的多种数据结构,本节讲述如何用之实现:链表、结构和树。biLLinux联盟
    1、(单)链表biLLinux联盟
        链表是一种比较简单的数据结构,可以按一定的次序存贮值。每个元素含有两个域,一个是值,一个是引用(或称指针),指向链表中下一个元素。一个特殊的头指针指向链表的第一个元素。biLLinux联盟
        在Perl中,链表很容易用关联数组实现,因为一个元素的值可以作为下一个元素的索引。下例为按字母顺序排列的单词链表:biLLinux联盟
    %words = ("abel", "baker", biLLinux联盟
    "baker", "charlie",biLLinux联盟
    "charlie", "delta",biLLinux联盟
    "delta", "");biLLinux联盟
    $header = "abel";biLLinux联盟
        上例中,简单变量$header含有链表中第一个单词,它同时也是关联数组第一个元素的下标,其值baker又是下一个元素的下标,依此类推。biLLinux联盟
        下标为delta的最后一个元素的值为空串,表示链表的结束。biLLinux联盟
        在将要处理的数据个数未知或其随程序运行而增长的情况下,链表十分有用。下例用链表按字母次序输出一个文件中的单词。biLLinux联盟
    1 : #!/usr/local/bin/perlbiLLinux联盟
    2 :biLLinux联盟
    3 : # initialize list to emptybiLLinux联盟
    4 : $header = "";biLLinux联盟
    5 : while ($line = <STDIN>) {biLLinux联盟
    6 :   # remove leading and trailing spacesbiLLinux联盟
    7 :   $line =~ s/^\s+|\s+$//g;biLLinux联盟
    8 :   @words = split(/\s+/, $line);biLLinux联盟
    9 :   foreach $word (@words) {biLLinux联盟
    10:     # remove closing punctuation, if anybiLLinux联盟
    11:     $word =~ s/[.,;:-]$//;biLLinux联盟
    12:     # convert all words to lower casebiLLinux联盟
    13:     $word =~ tr/A-Z/a-z/;biLLinux联盟
    14:     &add_word_to_list($word);biLLinux联盟
    15:   }biLLinux联盟
    16: }biLLinux联盟
    17: &print_list;biLLinux联盟
    18:biLLinux联盟
    19: sub add_word_to_list {biLLinux联盟
    20:   local($word) = @_;biLLinux联盟
    21:   local($pointer);biLLinux联盟
    22:biLLinux联盟
    23:   # if list is empty, add first itembiLLinux联盟
    24:   if ($header eq "") {biLLinux联盟
    25:     $header = $word;biLLinux联盟
    26:     $wordlist{$word} = "";biLLinux联盟
    27:     return;biLLinux联盟
    28:   }biLLinux联盟
    29:   # if word identical to first element in list,biLLinux联盟
    30:   # do nothingbiLLinux联盟
    31:   return if ($header eq $word);biLLinux联盟
    32:   # see whether word should be the newbiLLinux联盟
    33:   # first word in the listbiLLinux联盟
    34:   if ($header gt $word) {biLLinux联盟
    35:     $wordlist{$word} = $header;biLLinux联盟
    36:     $header = $word;biLLinux联盟
    37:     return;biLLinux联盟
    38:   }biLLinux联盟
    39:   # find place where word belongsbiLLinux联盟
    40:   $pointer = $header;biLLinux联盟
    41:   while ($wordlist{$pointer} ne "" &&biLLinux联盟
    42:     $wordlist{$pointer} lt $word) {biLLinux联盟
    43:     $pointer = $wordlist{$pointer};biLLinux联盟
    44:   }biLLinux联盟
    45:   # if word already seen, do nothingbiLLinux联盟
    46:   return if ($word eq $wordlist{$pointer});biLLinux联盟
    47:   $wordlist{$word} = $wordlist{$pointer};biLLinux联盟
    48:   $wordlist{$pointer} = $word;biLLinux联盟
    49: }biLLinux联盟
    50:biLLinux联盟
    51: sub print_list {biLLinux联盟
    52:   local ($pointer);biLLinux联盟
    53:   print ("Words in this file:\n");biLLinux联盟
    54:   $pointer = $header;biLLinux联盟
    55:   while ($pointer ne "") {biLLinux联盟
    56:     print ("$pointer\n");biLLinux联盟
    57:     $pointer = $wordlist{$pointer};biLLinux联盟
    58:   }biLLinux联盟
    59: }
        运行结果如下:biLLinux联盟
    Here are some words.biLLinux联盟
    Here are more words.biLLinux联盟
    Here are still more words.biLLinux联盟
    ^DbiLLinux联盟
    Words in this file:biLLinux联盟
    arebiLLinux联盟
    herebiLLinux联盟
    morebiLLinux联盟
    somebiLLinux联盟
    stillbiLLinux联盟
    words
        此程序分为三个部分:biLLinux联盟
  • 主程序:读取输入并转换到相应的格式。
  • 子程序:add_word_to_list,建立排序单词链表。
  • 子程序:print_list,输出单词链表
  •     第3~17行为主程序,第4行初始化链表,将表头变量$header设为空串,第5行起的循环每次读取一行输入,第7行去掉头、尾的空格,第8行将句子分割成单词。9~15行的内循环每次处理一个单词,如果该单词的最后一个字符是标点符号,就去掉。第13行把单词转换成全小写形式,第14行传递给子程序add_word_to_list。biLLinux联盟
        子程序add_word_to_list先在第24行处检查链表是否为空。如果是,第25行将单词赋给$header,26行创建链表第一个元素,存贮在关联数组%wordlist中。如果链表非空,37行检查第一个元素是否与该单词相同,如果相同,就立刻返回。下一步检查这一新单词是否应该为链表第一个元素,即其按字母顺序先于$header。如果是这样,则:biLLinux联盟
        1、创建一个新元素,下标为该新单词,其值为原第一个单词。biLLinux联盟
        2、该新单词赋给$header。biLLinux联盟
        如果该新单词不该为第一个元素,则40~44行利用局域变量$pointer寻找其合适的有效位置,41~44行循环到$wordlist{$pointer}大于或等于$word为止。接下来46行查看该单词是否已在链表中,如果在就返回,否则47~48行将其添加到链表中。首先47行创建新元素$wordlist{$word},其值为$wordlist{$pointer},这时$wordlist{$word}和$wordlist{$pointer}指向同一个单词。然后,48行将$wordlist{$pointer}的值赋为$word,即将$wordlist{$pointer}指向刚创建的新元素$wordlist{$word}。biLLinux联盟
        最后当处理完毕后,子程序print_list()依次输出链表,局域变量$pointer含有正在输出的值,$wordlist{$pointer}为下一个要输出的值。biLLinux联盟
        注:一般不需要用链表来做这些工作,用sort()和keys()在关联数组中循环就足够了,如:biLLinux联盟
    foreach $word (sort keys(%wordlist)) {biLLinux联盟
      # print the sorted list, or whatever }
        但是,这里涉及的指针的概念在其它数据结构中很有意义。biLLinux联盟
    2、结构biLLinux联盟
        许多编程语言可以定义结构(structure),即一组数据的集合。结构中的每个元素有其自己的名字,并通过该名字来访问。biLLinux联盟
        Perl不直接提供结构这种数据结构,但可以用关联数组来模拟。例如模拟C语言中如下的结构:biLLinux联盟
    struce{biLLinux联盟
      int field1;biLLinux联盟
      int field2;biLLinux联盟
      int field3; }mystructvar;
        我们要做的是定义一个含有三个元素的关联数组,下标分别为field1、field2、field3,如:biLLinux联盟
    %mystructvar = ("field1" , "" ,biLLinux联盟
          "field2" , "" ,biLLinux联盟
          "field3" , "" ,);
        像上面C语言的定义一样,这个关联数组%mystrctvar有三个元素,下标分别为field1、field2、field3,各元素初始值均为空串。对各元素的访问和赋值通过指定下标来进行,如:biLLinux联盟
        $mystructvar{"field1"} = 17;biLLinux联盟
    3、树biLLinux联盟
        另一个经常使用的数据结构是树。树与链表类似,但每个节点指向的元素多于一个。最简单的树是二叉树,每个节点指向另外两个元素,称为左子节点和右子节点(或称孩子),每个子节点又指向两个孙子节点,依此类推。biLLinux联盟
        注:此处所说的树像上述链表一样是单向的,每个节点指向其子节点,但子节点并不指向父节点。biLLinux联盟
        树的概念可以如下描述:biLLinux联盟
  • 因为每个子节点均为一个树,所以左/右子节点也称为左/右子树。(有时称左/右分支)
  • 第一个节点(不是任何节点的子节点的节点)称为树的根。
  • 没有孩子(子节点)的节点称为叶节点。
  •     有多种使用关联数组实现树结构的方法,最好的一种应该是:给子节点分别加上left和right以访问之。例如,alphaleft和alpharight指向alpha的左右子节点。下面是用此方法创建二叉树并遍历的例程:biLLinux联盟
    1 : #!/usr/local/bin/perlbiLLinux联盟
    2 :biLLinux联盟
    3 : $rootname = "parent";biLLinux联盟
    4 : %tree = ("parentleft", "child1",biLLinux联盟
    5 :          "parentright", "child2",biLLinux联盟
    6 :          "child1left", "grandchild1",biLLinux联盟
    7 :          "child1right", "grandchild2",biLLinux联盟
    8 :          "child2left", "grandchild3",biLLinux联盟
    9 :          "child2right", "grandchild4");biLLinux联盟
    10: # traverse tree, printing its elementsbiLLinux联盟
    11: &print_tree($rootname);biLLinux联盟
    12:biLLinux联盟
    13: sub print_tree {biLLinux联盟
    14:   local ($nodename) = @_;biLLinux联盟
    15:   local ($leftchildname, $rightchildname);biLLinux联盟
    16:biLLinux联盟
    17:   $leftchildname = $nodename . "left";biLLinux联盟
    18:   $rightchildname = $nodename . "right";biLLinux联盟
    19:   if ($tree{$leftchildname} ne "") {biLLinux联盟
    20:     &print_tree($tree{$leftchildname});biLLinux联盟
    21:   }biLLinux联盟
    22:   print ("$nodename\n");biLLinux联盟
    23:   if ($tree{$rightchildname} ne "") {biLLinux联盟
    24:     &print_tree($tree{$rightchildname});biLLinux联盟
    25:   }biLLinux联盟
    26: }
        结果输出如下:biLLinux联盟
    grandchild1biLLinux联盟
    child1biLLinux联盟
    grandchild2biLLinux联盟
    parentbiLLinux联盟
    grandchild3biLLinux联盟
    child2biLLinux联盟
    grandchild4
        

        注意函数print_tree()以次序“左子树、节点、右子树”来输出各节点的名字,这种遍历次序称为“左序遍历”。如果把第22行移到19行前,先输出节点明,再输出左子树、右子树,则为“中序遍历”,如果把第22行移到25行后,输出次序为左子树、右子树、节点,则为“右序遍历”。biLLinux联盟
        可以用同样的方法,即连接字符串构成下标,来创建其它的数据结构,如数据库等。

    Linux联盟收集整理 ,转贴请标明原始链接,如有任何疑问欢迎来本站Linux论坛讨论
    评论】【加入收藏夹】【 】【打印】【关闭
    ※ 相关链接
     ·Delphi中Hash表的使用方法  (2007-02-01 11:44:49)
     ·用 hashcash 打击垃圾邮件  (2005-11-30 09:13:01)