One liner: "&&" all elements of array

I

Irving Kimura

I must admit that one of the things I enjoy most about programming
Perl is also one of the most infamous: the possibility of compact
expressions that get a lot done with very few keystrokes. I'm
referring to gems like this one:

# removes duplicates from an array, preserving original order
@no_repeats = do { my %h; grep !$h{$_}++, @has_repeats };

....which I found recently in an old c.l.p.m. post, and which make
Pythonites clutch their heads and run out of the room screaming.

OK, so call such opaque compactness a guilty pleasure, to be enjoyed
only by consenting adults...

I'm looking for the most compact way in Perl to take the logical
and of all the elements of an array or list. The best I can come
up with is this:

!grep !$_, @array;

(The corresponding logical or is equally long:

!!grep $_, @array;

The initial !! ensures a scalar result even in a list context.)

I've also run into stuff like this

eval join '&', map $_ ? 1 : 0, @array;

....which is a bit klugey but functional, and generalizable to other
infix operators such as '|' and '+'. Then again, generalizability
earns one no points in the compactness derby. (The map is required
to take care of cases in which @array contains elements, such as
the empty string or undef or whitespace, that would mess up the
Perl string to be eval'd. And since we are now dealing with 1s
and 0s we can take the bit-wise and.)

I wonder if there's anything better, or I should say badder, out
there. >:)

Irv
 
B

Ben Morrow

Irving Kimura said:
# removes duplicates from an array, preserving original order
@no_repeats = do { my %h; grep !$h{$_}++, @has_repeats };

...which I found recently in an old c.l.p.m. post, and which make
Pythonites clutch their heads and run out of the room screaming.

Oh, come on, that's perfectly clear... :)
I'm looking for the most compact way in Perl to take the logical
and of all the elements of an array or list. The best I can come
up with is this:

!grep !$_, @array;

(The corresponding logical or is equally long:

!!grep $_, @array;

The initial !! ensures a scalar result even in a list context.)

The 'or' can be shortened by one character:

+grep $_, @array;

.. Other than that, I'd warrant these are the shortest for arbitrary
operands.

If you can guarantee 0 or 1, then "@array"!~/0/ works, with
"@array"=~/1/ for or; if you can further guarantee $"="" then
0+"@array" works for or.

Ben
 
I

Irving Kimura

In said:
The 'or' can be shortened by one character:
+grep $_, @array;

I thought of that, but when I try

perl -le 'print +grep $_, (1, 1)'

I get 11 as the printout, surprisingly enough...

After my original post, I realized that the grep-based solutions
have an additional virtue besides brevity. They do the right thing
if one wants to generalize the definition of the && and || operators
to the "pathological" cases of a single operand, and no operands:

sub And { !grep !$_, @_ }
sub Or { !!grep $_, @_ }
And(1) => 1
And(0) =>
And() => 1
Or(1) => 1
Or(0) =>
Or() =>

(There are analogous generalizations for the intersection and union
operators in set theory.)

So this way of implementing ands and ors is not only succinct but
also "mathematically correct" in some sense. Even Python-heads
have got to like that!

Irv
 
T

Tad McClellan

Irving Kimura said:
I'm looking for the most compact way in Perl to


That is called "Perl golf".

Mentioning "golf" in your subject would help draw in
the character-frugal type of Perl folks.
 

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

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top