Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

help manipulating data in an array.

by nightfreightpilot (Initiate)
on Nov 12, 2004 at 03:58 UTC ( #407265=perlquestion: print w/ replies, xml ) Need Help??
nightfreightpilot has asked for the wisdom of the Perl Monks concerning the following question:

1st..excellent site. I have only tonight stumbled upon what appears to be the plethora of perl information I have been searching for. I am late in life starting my programming journey, however there is no time like the present to start. Perl is my first language and the learning curve seems steep indeed. I am self-teaching using both the Sam's 24 book and the "Camel" book. I am in the first chapters.

With the assistance of Cingular, and cut/paste, I have created a file of all the phone numbers I've called. With my first real code, I would like to open that file and simply identify how many times I've called a particular number. Adding the minutes and such will come at a later time I suppose. I printed the file and manually determined the number of times I have called a number ending with 9432 to be 84 out of nearly 300 entries (for error checking purposes). The code I have written thus far follows:

open (CINGULAR, "c:/documents and Settings/david price/my documents/cingular.txt") || die "cannot open: $!"; @number=<CINGULAR>; close (CINGULAR); $count=0; while ($count<100) { if (@number=~[/^9432$/g]) { print "match found"; } else { print "match failed"; } $count++; }

Upon running, I receive the following errors:

Applying pattern match (m//) to @array will act on scalar (@array)at cingular.pl line 9....and Use of uninitialized value in pattern match +(m//) at cingular.pl line 9.

Obviously my code isn't running, but I'm not sure as to why. I've bound using ~...am looking from beginning to end of line for 9432....each time I look through a line the count in incrementing. Any help would be most welcome.

Thank you.

Edited by davido: Rescued formatting, supplied code tags.

Comment on help manipulating data in an array.
Select or Download Code
Re: help manipulating data in an array.
by atcroft (Monsignor) on Nov 12, 2004 at 04:06 UTC

    The reason for the error message is that when you performed the @number=<CINGULAR>;, you read the entire list into an array. This means you might have something like:

    $number[0] = '888-555-1212' $number[1] = '666-555-3456' $number[2] = '123-555-9432'

    More likely what you intended in your if statement was something $number[$count] rather than @number, as this would allow you to loop thru the elements.

    Hope that helps.

Re: help manipulating data in an array.
by pg (Canon) on Nov 12, 2004 at 04:18 UTC

    First as atcroft pointed out, you most likely wanted to m// an array element, not the array (or the size of the array in fact).

    Also, what if your array has less than 100 elements, in that case you would get error saying that you used unintialized value in m//. BTW, please use strict.

    You probably want something like this: (your code indicated that you want to look at the first 100 elemnts only, I assume this is true)

    use strict; use warnings; my @number = (1,2,3,9432, 5,6,7); my $count=0; for (0 .. (($#number < 99) ? $#number : 99)) { if ($number[$count]=~/^9432$/g) { print "match found\n"; } else { print "match failed\n"; } $count++; }

    Now a little bit more on m// with array. the m// will actually be performed on scalar(@array), which is the number of elements:

    use strict; use warnings; my @number1 = (2 .. 9432); my @number2 = (2 .. 9433); #I intentionally avoided the use of (1.. 94 +32) here, to remove the doubt whether it compares against the last el +ement of the array. my @number3 = (2 .. 9434); my $count=0; if (@number1 =~ /^9432$/g) { print "match found\n"; } else { print "match failed\n"; } if (@number2 =~ /^9432$/g) { print "match found\n"; } else { print "match failed\n"; } if (@number3 =~ /^9432$/g) { print "match found\n"; } else { print "match failed\n"; }
Re: help manipulating data in an array.
by Zaxo (Archbishop) on Nov 12, 2004 at 04:18 UTC

    Your error messages say what is wrong. The syntax @foo =~ m/$re/ does not do what you want it to.

    You should look at each line separately and try the lookup with each. I'd be inclined to use the index builtin instead of regex matching, since you have the particular number you want to look for. Here's what I'd do, sticking close to what you wrote,

    # after getting @number my $wanted = '9432'; for (@number[0..99]) { if (index($_, $wanted) != -1) { print "match found\n"; } else { print "match failed\n"; } }
    There are a couple of things there you may not have seen before. I used an array slice to limit the number of items searched, where you used a while loop. The other is the index function itself.

    After Compline,
    Zaxo

Re: help manipulating data in an array.
by larryp (Deacon) on Nov 12, 2004 at 04:48 UTC

    Try this:

    open (CINGULAR, "c:/documents and Settings/david price/my documents/ci +ngular.txt") || die "cannot open: $!"; @number=<CINGULAR>; close (CINGULAR); # Remove the following commented lines # $count=0; # while ($count<100) { # if (@number=~/^9432$/g) { # print "match found"; } # else { # print "match failed"; # } # $count++; # } # and change them to: foreach $line ( @number ) { if ( $line =~ /^9432$/g ) { print "Match found\n"; } else { print "Match failed\n"; } }

    The foreach loop allows you to loop through each element of the array, pull out one element at a time ($line), check it for the pattern, and print the appropriate message. You could add a counter in one or both sections of the conditional block to determine the number of matches/non-matches you get and print this as a summary at the end of the script. ( Beats manually counting up the "Match Found" and "Match Failed" lines in the DOS window. :) )

    You're going to want to rethink your regular expression, though. :) Think about what the ^ and $ anchors are do. The way you have it written right now, you will only get a match when the number 9432 is the only text in the line.

    HTH,

    /Larry

Re: help manipulating data in an array.
by injunjoel (Priest) on Nov 12, 2004 at 05:03 UTC
    Greetings all,
    A few suggestions...
    To access the variables that reside in your @number array you will need to refer to them as scalars so $number[0] would give you the first element of your array.
    To get the size of your array use scalar @number
    Now going through an array can be accomplished in a myriad of different ways but here are two of the more common ones aside from the while loop you already have.
    #the foreach style sets a variable, in this case $num, to #each element of your array. If you did not specify a #variable, then the special variable $_ would be set #each time through. foreach my $num (@number){ if($num =~ /9432$/){ print "match found"; }else{ print "match failed"; } } #a C-style for loop in which case you will be using #the $i variable to count from 0 to the end of your array #based on how big it is which we now know is scalar @number. for(my $i=0 ; $i < scalar @number ; $i++){ if($number[$i] =~ /9432$/){ print "match found"; }else{ print "match failed"; } }
    One last thing if you are looking for number ending in some sequence of digits, in this case '9432' you do not need to use the ^ anchor, just the $ anchor, since the ^ indicates to the regexp engine that you are checking from the beginning of the string. The $ indicates the end of the string, so your pattern would be /9432$/ since you are trying to match the end.
    I hope that helps.

    -InjunJoel

    "I do not feel obliged to believe that the same God who endowed us with sense, reason and intellect has intended us to forego their use." -Galileo
Re: help manipulating data in an array.
by TedPride (Priest) on Nov 12, 2004 at 07:39 UTC
    The simplest way to do this is as follows:
    use strict; use warnings; my (@numbers, $handle); open ($handle, "c:/documents and Settings/david price/my documents/cin +gular.txt") || die "cannot open: $!"; @numbers = <$handle>; close ($handle); for (@numbers) { if (index($_, '9432') != -1) { print "match found\n"; } else { print "match failed\n"; } }
    Use strict and use warnings will tell you if you do naughty things with your code, like forgetting to set scope on your variables (my means scope is inside the current block). Using (locally scoped) variables for your handles rather than names means your handle can't conflict with other handles; using a for loop on your lines means you don't have to mess with line numbers; using substr means your matching is much more efficient than if you used regular expressions.

    Line by line analysis of your code is as follows:

    open (CINGULAR, "c:/documents and Settings/david price/my documents/ci +ngular.txt") || die "cannot open: $!"; # USE VARIABLES FOR FILE HANDLES INSTEAD OF NAMED FILE HANDLES @number=<CINGULAR>; # DECLARE A SCOPE FOR ALL VARIABLES. my @number=<CINGULAR>; would be b +etter close (CINGULAR); $count=0; # SAME while ($count<100) { # IF YOU WANT TO LOOP THROUGH AN ARRAY, USE SOMETHING LIKE: # for (my $c = 0; $c <= $#number; $c++) { print $number[$c]; } # for (0..$#number) { print $number[$_]; } # for (@number) { print $_; } # foreach (@number) { print $_; } # $#number is the address of the last item in the array. # $_ is the default input / output variable. if (@number=~[/^9432$/g]) { # PROPER SYNTAX IS if ($number[$count] =~ /9432$/) { # The g flag is used for multiple matches; ^ and $ are only used toget +her # if you want a match at both ends - in other words, an exact match. # I don't know what the brackets were for. print "match found"; } else { print "match failed"; } $count++; # THIS IS FINE. HOWEVER, YOU COULD HAVE SAVED A STATEMENT BY DOING: # while ($count++ < 100) { }
Re: help manipulating data in an array.
by Anonymous Monk on Nov 12, 2004 at 13:21 UTC

    Others pointed out the mistakes with the match. I shall talk further improvements. Here's how I would do it:

    • I always use strict and use diagnostics so that Perl points out any dumb mistakes I make.
    • Instead of traditional filehandles (CINGULAR) I use a scalar variable ($fh). It does not matter in this small program, but in larger I can take advantage of limiting the scope of the variable so that it doesn't unnecessarily pollute the namespace.
    • I tell open to open the file for reading only with the <. Leaving it off means open for read/write, which can be dangerous if overlooked.
    • The idiom is open or die instead of the variant with the logical operator || which requires lots of parentheses because it has such a high operator precedence.
    • This is probably the most important hint: reading the whole file into an array to process it does not scale well. Once your file gets bigger than your RAM, the operating system must page out to disk and the program will become dog slow. A better approach is to read it line for line and process immediately.
    use strict; use diagnostics; open my $fh, "<c:/documents and Settings/david price/my documents/cing +ular.txt" or die "cannot open for reading: $!"; my $matches; while (<$fh>) { $matches++ if /9432$/; last if $. == 100; # skip to end of while once we have reached line 100 # $. is a built-in variable, see perlvar in the docs }; close $fh; print "Found $matches matches.\n";

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://407265]
Approved by atcroft
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (12)
As of 2014-10-23 11:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (125 votes), past polls