📄 ch04_13.htm
字号:
<HTML><HEAD><TITLE>Recipe 4.12. Finding the First List Element That Passes a Test (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:31:58Z"><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_12.htm"TITLE="4.11. Processing Multiple Elements of an Array"><LINKREL="next"HREF="ch04_14.htm"TITLE="4.13. Finding All Elements in an Array Matching Certain Criteria"></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_12.htm"TITLE="4.11. Processing Multiple Elements of an Array"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 4.11. Processing Multiple Elements of an Array"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_14.htm"TITLE="4.13. Finding All Elements in an Array Matching Certain Criteria"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 4.13. Finding All Elements in an Array Matching Certain Criteria"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch04-20097">4.12. Finding the First List Element That Passes a Test</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-1011">Problem <ACLASS="indexterm"NAME="ch04-idx-1000006718-0"></A><ACLASS="indexterm"NAME="ch04-idx-1000006718-1"></A></A></H3><PCLASS="para">You want the first element in the list (or its index) that passes a test. Alternatively, you want to know whether any element passes the test. The test can be simple identity ("Is this element in the list?")[<ACLASS="footnote"HREF="#ch04-pgfId-1000000590">1</A>] or more complex ("I have a list of Employee objects, sorted from highest salary to lowest. Which manager has the highest salary?"). Simple cases normally only require the value of the element, but when the array itself will be altered, you probably need to know the index number of the first matching element.</P><BLOCKQUOTECLASS="footnote"><DIVCLASS="footnote"><PCLASS="para"><ACLASS="footnote"NAME="ch04-pgfId-1000000590">[1]</A> But why didn't you use a hash then?</P></DIV></BLOCKQUOTE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-1017">Solution</A></H3><PCLASS="para">To find a matching value, use <CODECLASS="literal">foreach</CODE> to loop over every element, and call <CODECLASS="literal">last</CODE><ACLASS="indexterm"NAME="ch04-idx-1000006731-0"></A><ACLASS="indexterm"NAME="ch04-idx-1000006731-1"></A> as soon as you find a match:</P><PRECLASS="programlisting">my($match, $found, $item);foreach $item (@array) { if ($criterion) { $match = $item; # must save $found = 1; last; }}if ($found) { ## do something with $match} else { ## unfound}</PRE><PCLASS="para">To find a matching index, use <CODECLASS="literal">for</CODE> to loop a variable over every array index, and call <CODECLASS="literal">last</CODE> as soon as you find a match:</P><PRECLASS="programlisting">my($i, $match_idx);for ($i = 0; $i < @array; $i++) { if ($criterion) { $match_idx = $i; # save the index last; }}if (defined $match_idx) { ## found in $array[$match_idx]} else { ## unfound}</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-1077">Discussion</A></H3><PCLASS="para">Not having a built-in mechanism to do this, we must write our own code to go through the list and test each element. We use <CODECLASS="literal">foreach</CODE> and <CODECLASS="literal">for</CODE> and call <CODECLASS="literal">last</CODE> to ensure that we stop as soon as we find a match. Before we use <CODECLASS="literal">last</CODE> to stop looking, though, we save the value or index.</P><PCLASS="para">A common mistake is to try to use <CODECLASS="literal">grep</CODE> here. The problem is that <CODECLASS="literal">grep</CODE> always tests all elements and finds all matches, so it's inefficient if you only want the first match.</P><PCLASS="para">We have to set <CODECLASS="literal">$match</CODE> when we want the value of the first matching element. We can't just test <CODECLASS="literal">$item</CODE> at the end of the loop, because <CODECLASS="literal">foreach</CODE> automatically <CODECLASS="literal">local</CODE>izes the iterator variable and this prevents us from getting to its last loop value after the loop ends. See <ACLASS="xref"HREF="ch04_05.htm"TITLE="Doing Something with Every Element in a List">Recipe 4.4</A>.</P><PCLASS="para">Here's an example. Assume that <CODECLASS="literal">@employees</CODE> has a list of Employee objects, sorted in descending order by salary. We wish to find out the highest paid engineer, who will be the first engineer in the array. We only want to print the engineer's name, so we want the value, not the index.</P><PRECLASS="programlisting">foreach $employee (@employees) { if ( $employee->category() eq 'engineer' ) { $highest_engineer = $employee; last; }}print "Highest paid engineer is: ", $highest_engineer->name(), "\n";</PRE><PCLASS="para">When we're searching and only want the index, we can save some code by remembering that <CODECLASS="literal">$i</CODE> will not be an acceptable array index if we don't find a match. This mainly saves us code space, as not doing an assignment doesn't really win us much compared to the time we'll have spent testing the list elements. It's more obscure, because it tests <CODECLASS="literal">if</CODE> <CODECLASS="literal">($i</CODE> <CODECLASS="literal"><</CODE> <CODECLASS="literal">@ARRAY)</CODE> to check whether we found a match, instead of the more obvious <CODECLASS="literal">defined</CODE> test as in the previous Solution.</P><PRECLASS="programlisting">for ($i = 0; $i < @ARRAY; $i++) { last if $criterion;}if ($i < @ARRAY) { ## found and $i is the index} else { ## not found}</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch04-pgfId-1121">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 <CODECLASS="literal">grep</CODE> function in <ICLASS="filename">perlfunc </I>(1) and <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><ACLASS="indexterm"NAME="ch04-idx-1000006727-0"></A><ACLASS="indexterm"NAME="ch04-idx-1000006727-1"></A><ACLASS="indexterm"NAME="ch04-idx-1000006727-2"></A><ACLASS="indexterm"NAME="ch04-idx-1000006727-3"></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_12.htm"TITLE="4.11. Processing Multiple Elements of an Array"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 4.11. Processing Multiple Elements of an Array"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_14.htm"TITLE="4.13. Finding All Elements in an Array Matching Certain Criteria"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 4.13. Finding All Elements in an Array Matching Certain Criteria"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">4.11. Processing Multiple Elements of an Array</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.13. Finding All Elements in an Array Matching Certain Criteria</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 © 2002</a> O'Reilly & 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 + -