Noob trying to understand simple Perl grep statement

W

walterbyrd

This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array. I am
guessing that the @required array is what is being grep'd. But what is
$_ ? Is that also each item from the @required array? If so, why not
just use the $item variable again? And what does >>$_, @skipper<<
mean? What is with the comma? Is that supposed to mean: grep $item
@skipper?

Is this supposed to check if the skipper is missing any required item?
Why not:

unless (grep $item @required eq grep $item @skipper)
 
W

Willem

walterbyrd wrote:
) I don't understand this line:
)
) unless (grep $item eq $_, @skipper)

Let's break it into pieces then:

grep $item eq $_ , @skipper

grep <something> @skipper
Means: Return each item from @skipper for which <something> is true.

Furthermore, inside <something>, the variable $_ is the current item from
@skipper under consideration.

So:
grep $item eq $_ , @skipper

Means:
Return each item from @skipper for which >> $item eq $_ << is true.
Or in other words:
Return each item from @skipper that is equal to $item.

And the last bit is unless(), which means that the returned array is being
looked at as a truth value. An array is true if it contains elements.


Simple, huh ? Well, that's Perl for you. ;-)



SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
T

Tad J McClellan

Willem said:
walterbyrd wrote:
) I don't understand this line:
)
) unless (grep $item eq $_, @skipper)
And the last bit is unless(), which means that the returned array is being
looked at


There is no returned array. There is not even a returned list.

There is only the return value from grep() in a scalar context.

perldoc -f grep

In scalar context, returns the number of times the expression was true.
 
T

Tad J McClellan

walterbyrd said:
This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array. I am
guessing that the @required array is what is being grep'd.


No, the @skipper array is what is being grep'd.

But what is
$_ ?


One of the elements from the @skipper array.

And what does >>$_, @skipper<<
mean? What is with the comma?


That is the syntax for calling grep:

perldoc -f grep

=item grep EXPR,LIST

It says that a comma is required after the expression.

(The expression for grep() is the "$item eq $_" part above).

Is that supposed to mean: grep $item
@skipper?


No, because that would be a syntax error.

unless (grep $item @required eq grep $item @skipper)


More syntax errors...
 
J

John W. Krahn

walterbyrd said:
This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

That can also be written as:

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
my $count;
for $_ (@skipper) {
$count++ if $item eq $_;
}
unless ($count) { # not found in list?
print "skipper is missing $item.\n";
}
}
I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array. I am
guessing that the @required array is what is being grep'd.

No, the @skipper array is being grep'd.
But what is $_ ?

The value of the elements of @skipper.
Is that also each item from the @required array? If so, why not
just use the $item variable again? And what does >>$_, @skipper<<
mean? What is with the comma? Is that supposed to mean: grep $item
@skipper?

perldoc -f grep

grep EXPR,LIST
Is this supposed to check if the skipper is missing any required item?
Why not:

unless (grep $item @required eq grep $item @skipper)

Because Perl does not work that way.



John
 
X

xhoster

walterbyrd said:
This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

This would probably best be done with a hash rather than an array for at
least one of those structures.
I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array. I am
guessing that the @required array is what is being grep'd.

@skipper is what is being grepped. One time for each thing in @required
But what is
$_ ? Is that also each item from the @required array?

In the grep, $_ is set to each thing in the @skipper array in turn.
If so, why not
just use the $item variable again? And what does >>$_, @skipper<<
mean?

In this context, nothing. You broken down the code incorrectly. The
grouping is
($item eq $_), @skipper
not
$item eq ($_,skipper)

Where the parentheses are meta language that indicate grouping for our
discussion, not necessarily to be taken as literal Perl syntax.

What is with the comma? Is that supposed to mean: grep $item
@skipper?

No, it means (about) the same thing as:

grep {$item eq $_} @skipper.

You provide grep with either a block with no comma, then a list; or an
expression then comma then a list. That is just how grep works.

See perldoc -f grep:

grep BLOCK LIST
grep EXPR,LIST


Is this supposed to check if the skipper is missing any required item?

The overall code, yes. The grep part of the code just return a count
(Because it is invoked in a scalar context) of the things in @skipper which
equal whatever happens to be in $item at the moment. if the contents of
@skipper is unique, then this count will either be 0 (considered false) or
1 (considered true)
Why not:

unless (grep $item @required eq grep $item @skipper)

Because that wouldn't work. It is a syntax error at several levels,
and semantic error at several more.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
J

J.D. Baldwin

In the previous article said:
This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array. I am
guessing that the @required array is what is being grep'd. But what
is $_ ? Is that also each item from the @required array? If so, why
not just use the $item variable again? And what does >>$_,
@skipper<< mean? What is with the comma? Is that supposed to mean:
grep $item @skipper?

grep is taking two arguments, separated by the comma. They are:

1. $item eq $_

and

2. @skipper

The effect of this is to go through elements of @skipper, creating a
list out of the ones that equal $item (i.e., when the first arg
evaluates to "true." For any given $item, there will be only one
matching element (assuming items in @skipper are unique).

So, when $item is a member of @skipper, the grep will return a
one-element list consisting of that item. When $item is not found in
@skipper, the grep will return an empty list.

In the latter case, when grep returns an empty list, it will trigger
the block after the unless, printing the value of $item.
Is this supposed to check if the skipper is missing any required item?
Why not:

unless (grep $item @required eq grep $item @skipper)

OK, first off, grep requires a comma or a block to be syntactically
correct.

Second, the first argument of grep is a truth-test, which determines
whether each given element of the array argument is passed into the
result list. If $item is non-null, then

grep $item, @required

will just be the same as @required (since $item is always true for a
non-empty string).

A revised version of your line:

unless (grep $item, @required eq grep $item, @skipper)

still has problems because the expression will be true if @required
and @skipper evaluate to the same value in scalar context. Probably
not what you intended.
 
J

Jürgen Exner

walterbyrd said:
This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array.
Correct.

I am
guessing that the @required array is what is being grep'd.

Wrong. It is the @skipper array, that is filtered. After all, that is
the one, that is passed as argument to grep.
But what is
$_ ? Is that also each item from the @required array?

No, it is subsequently set to each element of @skipper to test if $item
is equal to that element.
If so, why not
just use the $item variable again? And what does >>$_, @skipper<<
mean? What is with the comma?

You are reading it wrong, adding some parenthesis to make the precedence
clearer:
grep ( {$item eq $_},
@skipper);

jue
 
T

Tad J McClellan

J.D. Baldwin said:
If $item is non-null, then

grep $item, @required

will just be the same as @required (since $item is always true for a
non-empty string).


$item = '0'; # a non-empty string that is NOT true...
 
S

sln

This is from the perl objects book.

my @required = qw(preserver sunscreen water_bottle jacket);
my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
for my $item (@required) {
unless (grep $item eq $_, @skipper) { # not found in list?
print "skipper is missing $item.\n";
}
}

I don't understand this line:

unless (grep $item eq $_, @skipper)

I understand that $item is each item in the @required array. I am
guessing that the @required array is what is being grep'd. But what is
$_ ? Is that also each item from the @required array? If so, why not
just use the $item variable again? And what does >>$_, @skipper<<
mean? What is with the comma? Is that supposed to mean: grep $item
@skipper?

Is this supposed to check if the skipper is missing any required item?
Why not:

unless (grep $item @required eq grep $item @skipper)

I don't know what book that is but it looks like you are trying
to find the intersection of two arrays, which is a FAQ here somewhere.

Understand that grep just searches the ENTIRE array for whatever it is
you wan't to find. Each time it finds whatever it is, it collects that
element into an array. In list/scalar context, returns list or count of
matched elements.

This is very inefficient. Whatever grep returns in the list should be
considerred read-only as well.

This from perlfunc:

Similarly, grep returns aliases into the original list, much as a for
loop's index variable aliases the list elements. That is, modifying an
element of a list returned by grep (for example, in a foreach, map or
another grep) actually modifies the element in the original list.
This is usually something to be avoided when writing clear code.

In my opinion, this is a major fopah. Only because it aliases en masse,
as opposed to a temporary itterator.

Perl grep() is no different than itterating over an ENTIRE array and searching
for a conditional. If want array, the intermediate variable $_ (an alias for
the list element) is pushed onto a temporary array. If count, the count is tracked.
Then returned. There is no way to break out of it, it plods along, mindleslly checking
every element. This is ok when the possiblity exists on variable pattern matching,
but when searching for a single existence, not so good.

So grep would be the slowest in your case.
A quicker method is this:

for $req_item (@required)
{
$found = 0;
for $skip_item (@skipper)
{
next if ($req_item ne $skip_item);
$found = 1;
last; # <- see, you wan't last, why continue?
}
print "skipper is missing $req_item.\n" if (!found);
}

So then, say you wan't something a little quicker.
Move up to a hash:

%skipper;
for $key (@skipper)
{
$skipper{$key}++;
}
for $req_item (@required)
{
if (!exists ($skipper{$req_item})
{
print "skipper is missing $req_item.\n"
}
}

If you have very large arrays, with very large words,
you might even be able to set up a binary search mechanism,
half, half again, then again, and again, etc..

Good luck!

sln
 
W

walterbyrd

I don't know what book that is but it looks like you are trying

The book is called: "Learning Perl Objects, References, and Modules."
The book is supposed to pick up where "Learning Perl" left off. I read
"Learning Perl" and consider it to be a great book.

I found out the book has been updated, the new book is called
"Intermediate Perl" so I got the new book.

I am presently trying to read, and understand, the stuff about
referencing, and de-referencing, arrays. And it is giving me a serious
headache.
 
S

sln

The book is called: "Learning Perl Objects, References, and Modules."
The book is supposed to pick up where "Learning Perl" left off. I read
"Learning Perl" and consider it to be a great book.

I found out the book has been updated, the new book is called
"Intermediate Perl" so I got the new book.

I am presently trying to read, and understand, the stuff about
referencing, and de-referencing, arrays. And it is giving me a serious
headache.

I wouldn't think too hard on references. Its actually the 'syntax' for
de-referencing in the doc's that makes most readers candidates for thorozine.

The Perl universe is so cluttered with 'meta' it makes deciphering code almost
impossible. The reason boils down to one thing: "One-liners". Yep, the little thing
penchant Perl fanatics drivel over and one-up each other with.

In reality, it is so busy because some dope decided to let people think short
contractions with 'meta' will give some other dope the illusion his/her code
is not only spiffy and unintelligable, but (this is the worst) will somehow
magically run faster. Emacs on steriods, but let's let it be syntactically
part of the language.

Hey well, give enough rope, get a good hanging.

References are very easy if you don't read too much into it.

Keep at it and good luck!


sln
 
R

Randal L. Schwartz

sln> In reality, it is so busy because some dope decided to let people think
sln> short contractions with 'meta' will give some other dope the illusion
sln> his/her code is not only spiffy and unintelligable, but (this is the
sln> worst) will somehow magically run faster. Emacs on steriods, but let's
sln> let it be syntactically part of the language.

I still regret inventing JAPHs, which encouraged obfuperl, and in some
sense was the motivation for Perl golf. All three items today harm Perl's
public perception more than they help, and I'm sad for that.

print "Just another Perl hacker,"; # the original
 
T

Tim Greer

Greg said:
Worrying about people who *choose* to be ignorant, as with any
form of bigotry, is a complete waste of time. Don't try to teach
a pig to dance, as the saying goes.

Alright then, I won't interrupt your reply to Randal about what you
feel.
 
C

C.DeRykus

: I still regret inventing JAPHs, which encouraged obfuperl, and in
: some sense was the motivation for Perl golf. All three items
: today harm Perl's public perception more than they help, and I'm
: sad for that.

Don't be a puritan. Perl is fun, and that's great! Snobs who look
down their noses at jam sessions aren't worth worrying about.

I agree totally. Dismissive comments are for snobs -- Perl brings fun
back to programming. And seriously, an "Obfuscated C Contest" or a
Perl "golf" contest is often
serendipitous because you're looking in a language's nooks and
crannies to explore its capabilities. At times the bugs and mis-
features of a languare are exposed; at others, you reveal how the
gears and gizmos work under the covers. The "Obfuscated C contest"
regularly attracts world class C programmers. Larry's won a couple of
times as I recall.
Just think.. Perl may have been the result of his mis-spent
youth :)
 
C

C.DeRykus

That's all very well, and indeed amusing and fun in the right place.
Unfortunately people do write obfuscated code in the wrong place and at
the wrong time. Sadly, about four years ago, and after repeated warnings,
I eventually had to sack someone who continued to write obfuscated code in
our application programs. He was merely one of a team of five programmers
working on the same system, all of whom at some point would have had to
amend that code. There are people on that team now who were not in the
company at the time, those programs are still being updated and amended,
and it would have been grossly unfair to them, and the rest of the team,
to have allowed him to continue to do so.

Be careful, be sensible!

Good advice. But, obfuscated code can be written
in all the langugages I'm aware of. Clearly, there are
major benefits to exploration and a sense of fun with
language. No one here is advocating "golf" constructs
for production code.

Sadly, though, the "O" word is often hurled by language
zealots arguing their special agendas and attempting
to sway the uninformed. Perl 6 should help with that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top