⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch05_05.htm

📁 By Tom Christiansen and Nathan Torkington ISBN 1-56592-243-3 First Edition, published August 1998
💻 HTM
字号:
<HTML><HEAD><TITLE>Recipe 5.4. Traversing a Hash (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:32:33Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch05_01.htm"TITLE="5. Hashes"><LINKREL="prev"HREF="ch05_04.htm"TITLE="5.3. Deleting from a Hash"><LINKREL="next"HREF="ch05_06.htm"TITLE="5.5. Printing a Hash"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch05_04.htm"TITLE="5.3. Deleting from a Hash"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 5.3. Deleting from a Hash"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch05_01.htm"TITLE="5. Hashes"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch05_06.htm"TITLE="5.5. Printing a Hash"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 5.5. Printing a Hash"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch05-37034">5.4. Traversing a Hash</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch05-pgfId-386">Problem<ACLASS="indexterm"NAME="ch05-idx-1000006438-0"></A><ACLASS="indexterm"NAME="ch05-idx-1000006438-1"></A></A></H3><PCLASS="para">You want to perform an action on each entry (i.e., each key-value pair) in a hash.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch05-pgfId-392">Solution</A></H3><PCLASS="para">Use <CODECLASS="literal">each</CODE> with a <CODECLASS="literal">while</CODE> loop:</P><PRECLASS="programlisting">while(($key, $value) = each(%HASH)) {    # do something with $key and $value}</PRE><PCLASS="para">Or use <CODECLASS="literal">keys</CODE><ACLASS="indexterm"NAME="ch05-idx-1000006451-0"></A> with a <CODECLASS="literal">foreach</CODE> loop, unless the hash is potentially very large:</P><PRECLASS="programlisting">foreach $key (keys %HASH) {    $value = $HASH{$key};    # do something with $key and $value}</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch05-pgfId-414">Discussion</A></H3><PCLASS="para">Here's a simple example, iterating through the <CODECLASS="literal">%food_color</CODE> hash from the introduction.</P><PRECLASS="programlisting"># %food_color per the introductionwhile(($food, $color) = each(%food_color)) {    print &quot;$food is $color.\n&quot;;}<CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Banana is yellow.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Apple is red.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Carrot is orange.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Lemon is yellow.</I></CODE></B></CODE>foreach $food (keys %food_color) {    my $color = $food_color{$food};    print &quot;$food is $color.\n&quot;;}<CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Banana is yellow.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Apple is red.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Carrot is orange.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Lemon is yellow.</I></CODE></B></CODE></PRE><PCLASS="para">We didn't really need the <CODECLASS="literal">$color</CODE> variable in the <CODECLASS="literal">foreach</CODE> example because we only use it once. Instead, we could have just written:</P><PRECLASS="programlisting"><CODECLASS="literal">print</CODE> <CODECLASS="literal">&quot;$food</CODE> <CODECLASS="literal">is</CODE> <CODECLASS="literal">$food_color{$food}.\n&quot;</CODE> </PRE><PCLASS="para">Every time <CODECLASS="literal">each</CODE> is called on the same hash, it returns the "next" key-value pair. We say "next" because the pairs are returned in the order the underlying lookup structure imposes on them, and this order is almost never alphabetic or numeric. When <CODECLASS="literal">each</CODE> runs out of hash elements, it returns the empty list <CODECLASS="literal">()</CODE>, which tests false and terminates the <CODECLASS="literal">while</CODE> loop.</P><PCLASS="para">The <CODECLASS="literal">foreach</CODE> example uses <CODECLASS="literal">keys</CODE>, which constructs an entire list containing every key from hash, before the loop even begins executing. The advantage to using <CODECLASS="literal">each</CODE> is that it gets the keys and values one pair at a time. If the hash contains many keys, not having to pre-construct a complete list of them can save substantial memory. The <CODECLASS="literal">each</CODE> function, however, doesn't let you control the order in which pairs are processed.</P><PCLASS="para">Using <CODECLASS="literal">foreach</CODE> and <CODECLASS="literal">keys</CODE> to loop over the list lets you impose an order. For instance, if we wanted to print the food names in alphabetical order:</P><PRECLASS="programlisting">foreach $food (sort keys %food_color) {    print &quot;$food is $food_color{$food}.\n&quot;;}<CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Apple is red.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Banana is yellow.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Carrot is orange.</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>Lemon is yellow.</I></CODE></B></CODE></PRE><PCLASS="para">This is a common use of <CODECLASS="literal">foreach</CODE>. We use <CODECLASS="literal">keys</CODE> to obtain a list of keys in the hash, and then we use <CODECLASS="literal">foreach</CODE> to iterate over them. The danger is that if the hash contains a large number of elements, the list returned by <CODECLASS="literal">keys</CODE> will use a lot of memory. The trade-off lies between memory use and the ability to process the entries in a particular order. We cover sorting in more detail in <ACLASS="xref"HREF="ch05_10.htm"TITLE="Sorting a Hash">Recipe 5.9</A>.</P><PCLASS="para">Because <CODECLASS="literal">keys</CODE>, <CODECLASS="literal">values</CODE>, and <CODECLASS="literal">each</CODE> all use the same internal data structures, be careful about mixing calls to these functions or prematurely exiting an <CODECLASS="literal">each</CODE> loop. Each time you call <CODECLASS="literal">keys</CODE> or <CODECLASS="literal">values</CODE>, the current location for <CODECLASS="literal">each</CODE> is reset. This code loops forever, printing the first key returned by <CODECLASS="literal">each</CODE>:</P><PRECLASS="programlisting">while ( ($k,$v) = each %food_color ) {    print &quot;Processing $k\n&quot;;    keys %food_color;               # goes back to the start of %food_color}</PRE><PCLASS="para">Modifying a hash while looping over it with <CODECLASS="literal">each</CODE> or <CODECLASS="literal">foreach</CODE> is, in general, fraught with danger. The <CODECLASS="literal">each</CODE> function can behave differently with <CODECLASS="literal">tie</CODE>d and untied hashes when you add or delete keys from a hash. A <CODECLASS="literal">foreach</CODE> loops over a pre-generated list of keys, so once the loop starts, <CODECLASS="literal">foreach</CODE> can't know whether you've added or deleted keys. Keys added in the body of the loop aren't automatically appended to the list of keys to loop over, nor are keys deleted by the body of the loop deleted from this list.</P><PCLASS="para"><ACLASS="xref"HREF="ch05_05.htm#ch05-34568"TITLE="countfrom">Example 5.1</A> reads a mailbox file and reports on the number of messages from each person. It uses the <CODECLASS="literal">From:</CODE> line to determine the sender. (It isn't smart in this respect, but we're showing hash manipulation, not mail-file processing.) Supply the mailbox filename as a command-line argument, or use <CODECLASS="literal">&quot;-&quot;</CODE> to indicate you're piping the mailbox to the program.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch05-34568">Example 5.1: countfrom</A></H4><PRECLASS="programlisting">#!/usr/bin/perl# countfrom - count number of messages from each sender$filename = $ARGV[0] || &quot;-&quot;;open(FILE, &quot;&lt;$filename&quot;)            or die &quot;Can't open $filename : $!&quot;;while(&lt;FILE&gt;) {    if (/^From: (.*)/) { $from{$1}++ }}foreach $person (sort keys %from) {    print &quot;$person: $from{$person}\n&quot;;}</PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch05-pgfId-518">See Also</A></H3><PCLASS="para">The <CODECLASS="literal">each</CODE> and <CODECLASS="literal">keys</CODE> functions in <EMCLASS="emphasis">perlfunc </EM>(1) and in <ACLASS="olink"HREF="../prog/ch03_01.htm">Chapter 3</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>; we talk about for and foreach in <ACLASS="xref"HREF="ch04_06.htm"TITLE="Iterating Over an Array by Reference">Recipe 4.5</A><ACLASS="indexterm"NAME="ch05-idx-1000006440-0"></A><ACLASS="indexterm"NAME="ch05-idx-1000006440-1"></A><ACLASS="indexterm"NAME="ch05-idx-1000006440-2"></A></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch05_04.htm"TITLE="5.3. Deleting from a Hash"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 5.3. Deleting from a Hash"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch05_06.htm"TITLE="5.5. Printing a Hash"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 5.5. Printing a Hash"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">5.3. Deleting from a Hash</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">5.5. Printing a Hash</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright &copy; 2002</a> O'Reilly &amp; Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -