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

📄 ch04_05.htm

📁 By Tom Christiansen and Nathan Torkington ISBN 1-56592-243-3 First Edition, published August 1998
💻 HTM
字号:
<HTML><HEAD><TITLE>Recipe 4.4. Doing Something with Every Element in a List (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:31:13Z"><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="ch04_01.htm"TITLE="4. Arrays"><LINKREL="prev"HREF="ch04_04.htm"TITLE="4.3. Changing Array Size"><LINKREL="next"HREF="ch04_06.htm"TITLE="4.5. Iterating Over an Array by Reference"></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="ch04_04.htm"TITLE="4.3. Changing Array Size"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 4.3. Changing Array Size"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch04_01.htm"TITLE="4. Arrays"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch04_06.htm"TITLE="4.5. Iterating Over an Array by Reference"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 4.5. Iterating Over an Array by Reference"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch04-18004">4.4. Doing Something with Every Element in a List</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-397">Problem <ACLASS="indexterm"NAME="ch04-idx-1000006630-0"></A><ACLASS="indexterm"NAME="ch04-idx-1000006630-1"></A></A></H3><PCLASS="para">You want to repeat a procedure for every element in a list.</P><PCLASS="para">Often you use an array to collect information you're interested in; for instance, login names of users who have exceeded their disk quota. When you finish collecting the information, you want to process it by doing something with every element in the array. In the disk quota example, you might send each user a stern mail message.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-405">Solution</A></H3><PCLASS="para">Use a <CODECLASS="literal">foreach</CODE> loop:</P><PRECLASS="programlisting">foreach $item (LIST) {    # do something with $item}</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-417">Discussion</A></H3><PCLASS="para">Let's say we've used <CODECLASS="literal">@bad_users</CODE> to compile a list of users over their allotted disk quota. To call some <CODECLASS="literal">complain()</CODE> subroutine for each one we'd use:</P><PRECLASS="programlisting">foreach $user (@bad_users) {        complain($user);}</PRE><PCLASS="para">Rarely is this recipe so simply applied. Instead, we often use functions to generate the list:</P><PRECLASS="programlisting">foreach $var (sort keys %ENV) {    print &quot;$var=$ENV{$var}\n&quot;;}</PRE><PCLASS="para">Here we're using <CODECLASS="literal">sort</CODE> and <CODECLASS="literal">keys</CODE> to build a sorted list of environment variable names. In situations where the list will be used more than once, you'll obviously keep it around by saving in an array. But for one-shot processing, it's often tidier to process the list directly.</P><PCLASS="para">Not only can we add complexity to this formula by building up the list in the <CODECLASS="literal">foreach</CODE>, we can also add complexity by doing more work inside the code block. A common application of <CODECLASS="literal">foreach</CODE> is to gather information on every element of a list, and then decide (based on that information) whether to do something. For instance, returning to the disk quota example:</P><PRECLASS="programlisting">foreach $user (@all_users) {    $disk_space = get_usage($user);     # find out how much disk space in use    if ($disk_space &gt; $MAX_QUOTA) {     # if it's more than we want ...        complain($user);                # ... then object vociferously    }}</PRE><PCLASS="para">More complicated program flow is possible. The code can call <CODECLASS="literal">last</CODE> to jump out of the loop, <CODECLASS="literal">next</CODE> to move on to the next element, or <CODECLASS="literal">redo</CODE> to jump back to the first statement inside the block. Use these to say "no point continuing with this one, I know it's not what I'm looking for" (<CODECLASS="literal">next</CODE>), "I've found what I'm looking for, there's no point in my checking the rest" (<CODECLASS="literal">last</CODE>), or "I've changed some things, I'd better do my tests and calculations again" (<CODECLASS="literal">redo</CODE>).</P><PCLASS="para"><ACLASS="indexterm"NAME="ch04-idx-1000006637-0"></A><ACLASS="indexterm"NAME="ch04-idx-1000006637-1"></A><ACLASS="indexterm"NAME="ch04-idx-1000006637-2"></A>The variable set to each value in the list is called a <EMCLASS="emphasis">loop variable</EM> or <EMCLASS="emphasis">iterator variable</EM>. If no iterator variable is supplied, the global variable <CODECLASS="literal">$_</CODE> is used. <CODECLASS="literal">$_</CODE> is the default variable for many of Perl's string, list, and file functions. In brief code blocks, omitting <CODECLASS="literal">$_</CODE> improves readability. (In long ones, though, too much implicit use hampers readability.) For example:</P><PRECLASS="programlisting">foreach (`who`) {    if (/tchrist/) {        print;    }}</PRE><PCLASS="para">or combining with a <CODECLASS="literal">while</CODE> loop:</P><PRECLASS="programlisting">while (&lt;FH&gt;) {              # $_ is set to the line just read    chomp;                  # $_ has a trailing \n removed, if it had one    foreach (split) {       # $_ is split on whitespace, into @_                            # then $_ is set to each chunk in turn        $_ = reverse;       # the characters in $_ are reversed        print;              # $_ is printed    }}</PRE><PCLASS="para">Perhaps all these uses of <CODECLASS="literal">$_</CODE> are starting to make you nervous. In particular, the <CODECLASS="literal">foreach</CODE> and the <CODECLASS="literal">while</CODE> both give values to <CODECLASS="literal">$_</CODE>. You might fear that at the end of the <CODECLASS="literal">foreach</CODE>, the full line as read into <CODECLASS="literal">$_</CODE> with <CODECLASS="literal">&lt;FH&gt;</CODE> would be forever gone.</P><PCLASS="para">Fortunately, your fears would be unfounded, at least in this case. Perl won't permanently clobber <ACLASS="indexterm"NAME="ch04-idx-1000007741-0"></A><CODECLASS="literal">$_</CODE>'s old value, because the <CODECLASS="literal">foreach</CODE>'s iterator variable (<CODECLASS="literal">$_</CODE> in this case) is automatically preserved during the loop. It saves away any old value on entry and restores it upon exit.</P><PCLASS="para">There is cause for some concern though. If the <CODECLASS="literal">while</CODE> had been the inner loop and the <CODECLASS="literal">foreach</CODE> the outer one, then your fears would have been realized. Unlike a <CODECLASS="literal">foreach</CODE> loop, the <CODECLASS="literal">while</CODE> <CODECLASS="literal">&lt;FH&gt;</CODE> construct clobbers the value of the global <CODECLASS="literal">$_</CODE> without first localizing it! So any routine&nbsp;- or block for that matter&nbsp;- that uses such a construct with <CODECLASS="literal">$_</CODE> should always declare <CODECLASS="literal">local</CODE> <CODECLASS="literal">$_</CODE> at its front.</P><PCLASS="para">If a lexical variable (one declared with <CODECLASS="literal">my</CODE>) is in scope, the temporary variable will be lexically scoped, private to that loop. Otherwise, it will be a dynamically scoped global variable. To avoid strange magic at a distance, as of release 5.004 you can write this more obviously and more clearly as:</P><PRECLASS="programlisting">foreach my $item (@array) {    print &quot;i = $item\n&quot;;}</PRE><PCLASS="para">The <CODECLASS="literal">foreach</CODE> looping construct has another feature: each time through the loop, the iterator variable becomes not a copy of but rather an<ACLASS="indexterm"NAME="ch04-idx-1000006638-0"></A> <EMCLASS="emphasis">alias</EM> for the current element. This means that when you change that iterator variable, you really change each element in the list:</P><PRECLASS="programlisting">@array = (1,2,3);foreach $item (@array) {    $item--;}print &quot;@array\n&quot;;<CODECLASS="userinput"><B><CODECLASS="replaceable"><I>0 1 2</I></CODE></B></CODE># multiply everything in @a and @b by seven@a = ( .5, 3 ); @b =( 0, 1 );foreach $item (@a, @b) {    $item *= 7;}print &quot;@a @b\n&quot;;<CODECLASS="userinput"><B><CODECLASS="replaceable"><I>3.5 21 0 7</I></CODE></B></CODE></PRE><PCLASS="para">This aliasing means that using a <CODECLASS="literal">foreach</CODE> loop to modify list values is both more readable and faster than the equivalent code using a three-part <CODECLASS="literal">for</CODE> loop and explicit indexing would be. This behavior is a feature, not a bug, that was introduced by design. If you didn't know about it, you might accidentally change something. Now you know about it.</P><PCLASS="para">For example, if we used <CODECLASS="literal">s///</CODE> on elements of the list returned by the <CODECLASS="literal">values</CODE> function, we would only be changing copies, not the real hash itself. The hash slice (<CODECLASS="literal">@hash{keys</CODE> <CODECLASS="literal">%hash}</CODE> is a hash slice, explained in <ACLASS="xref"HREF="ch05_01.htm"TITLE="Hashes">Chapter 5, <CITECLASS="chapter">Hashes</CITE></A>), however, gives us something we <EMCLASS="emphasis">can</EM> usefully change:</P><PRECLASS="programlisting"># trim whitespace in the scalar, the array, and all the values# in the hashforeach ($scalar, @array, @hash{keys %hash}) {    s/^\s+//;    s/\s+$//;}</PRE><PCLASS="para">For reasons hearkening back to the equivalent construct in the Unix Bourne shell, the <CODECLASS="literal">for</CODE> and <CODECLASS="literal">foreach</CODE> keywords are interchangeable:</P><PRECLASS="programlisting">for $item (@array) {  # same as foreach $item (@array)    # do something}for (@array)      {   # same as foreach $_ (@array)    # do something}</PRE><PCLASS="para">This style often indicates that its author writes or maintains shell scripts, perhaps for Unix systems administration. As such, their life is probably hard enough, so don't speak too harshly of them. Remember, TMTOWTDI. This is just one of those ways.</P><PCLASS="para">If you aren't fluent in Bourne shell, you might find it clearer to express "for each <CODECLASS="literal">$thing</CODE> in this <CODECLASS="literal">@list</CODE>," by saying <CODECLASS="literal">foreach</CODE> to make your code less like the shell and more like English. (But don't try to make your English look like your code!)</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-567">See Also</A></H3><PCLASS="para">The "For Loops," "Foreach Loops," and "Loop Control" sections of <ICLASS="filename">perlsyn </I>(1) and <ACLASS="olink"HREF="../prog/ch02_01.htm">Chapter 2</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>; the "Temporary Values via local(  )" section of <ICLASS="filename">perlsub</I> (1); the <ACLASS="olink"HREF="../prog/ch02_06.htm#PERL2-CH-2-SECT-6.8">"Scoped Declarations"</A> section of <ACLASS="olink"HREF="../prog/ch02_01.htm">Chapter 2</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>; we talk about <CODECLASS="literal">local()</CODE> in <ACLASS="xref"HREF="ch10_14.htm"TITLE="Saving Global Values">Recipe 10.13</A>; we talk about <CODECLASS="literal">my()</CODE> in <ACLASS="xref"HREF="ch10_03.htm"TITLE="Making Variables Private to a Function">Recipe 10.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="ch04_04.htm"TITLE="4.3. Changing Array Size"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 4.3. Changing Array Size"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="ch04_06.htm"TITLE="4.5. Iterating Over an Array by Reference"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 4.5. Iterating Over an Array by Reference"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">4.3. Changing Array Size</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">4.5. Iterating Over an Array by Reference</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 + -