Re: Concise foreach expression
by LanX (Saint) on Aug 29, 2014 at 12:12 UTC
|
You are trying to combine postfix foreach and postfix if and running into two problems:
- they can't be chained
- they can't use loop-vars other than $_
Your best bet for a concise expressions to be chained are map and grep
print grep { /test/ } @names
update
N.B.: you are still limited to $_
update
which means you won't have much use of nested loops with map
Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
my @list = (
["Barney", "Rubble"],
["Fred", "Flintstone"],
["Betty", "Rubble"],
["Wilma", "Flintstone"]
);
map {
say "Outer map before: @$_";
map { 1 } @$_;
say "Outer map after : @$_";
} @list;
But perhaps there's other pitfalls, so I'd be grateful for any enlightenment.
| [reply] [Watch: Dir/Any] [d/l] |
|
The problem happens when you need to use the $_ from the outer map in the inner map, as in the following contrived example:
my %tree = (
child1 => {},
child2 => {
grandchild1 => { brood3 => {} },
grandchild2 => { brood1 => {}, brood2 => {} },
},
);
say for 'Grandchildren:',
map {
my $x = $_; # <--- remove me!
"$_: " . (ref $tree{$_} ? join ', ' =>
map keys %{ $tree{$x}{$_} },
keys %{ $tree{$_} }
: q())
} keys %tree;
| [reply] [Watch: Dir/Any] [d/l] |
|
> Could you explain what you mean there?
I was talking about chaining maps or fors to simulate nested foreach loops.
I.o.w. list comprehensions are very hard to implement in Perl without nested blocks.
e.g. try to implement this Python example for "Pythagorean triples" w/o nesting
>>> [(x,y,z) for x in range(1,30) for y in range(x,30) for z in range(
+y,30) if x**2 + y**2 == z**2]
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12,
+ 15), (10, 24, 26), (12, 16, 20), (15, 20, 25), (20, 21, 29)]
Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
| [reply] [Watch: Dir/Any] [d/l] |
|
|
Re: Concise foreach expression
by AppleFritter (Vicar) on Aug 29, 2014 at 12:13 UTC
|
Unfortunately, statement modifiers cannot be chained. From perlsyn (emphasis in original):
Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending).
In this specific case, you can use grep or map instead, though.
say foreach (grep /test$/, @names);
map { /test$/ and say } @names;
Edit: toolic's remark in Re^2: Concise foreach expression also applies to the above two lines: they'll print the matching @names, not multiple copies of $path_name.
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
Re: Concise foreach expression
by toolic (Bishop) on Aug 29, 2014 at 12:14 UTC
|
Your original foreach loop is probably the clearest, but if you do want fewer characters, you could go for something less readable like:
print"$path_name\n"for grep/test$/,@names;
I doubt it runs faster. | [reply] [Watch: Dir/Any] [d/l] |
|
print"$path_name\n"x grep/test$/,@names;
say$path_name x grep/test$/,@names;
/test$/&&print$path_name,$/for@names;
/test$/&&say$path_name for@names;
If he meant $x where he had $path_name,
print"$_\n"x grep/test$/,@names;
say for grep/test$/,@names;
/test$/&&print$_,$/for@names;
/test$/&&say for@names;
print/.*test$/g,$/ for@names;
say/.*test$/g for@names;
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Concise foreach expression
by hdb (Monsignor) on Aug 29, 2014 at 12:13 UTC
|
print "$_\n" for grep {/test$/} @names;
UPDATE: ...or more cryptically: /test$/ and print "$_\n" for @names;.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
That produces different results from the OP's code. Yours prints out elements of the @names array, but the OP prints out $path_name multiple times.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
Re: Concise foreach expression
by johngg (Canon) on Aug 29, 2014 at 12:24 UTC
|
I agree that grep is the way to tackle this but just to show another way with a ternary as the argument to print and a statement modifier.
$ perl -Mstrict -Mwarnings -E '
my @arr = qw{ sdyudf attest reer fittest };
print m{test} ? qq{$_\n} : () for @arr;'
attest
fittest
$
I hope this is of interest.
| [reply] [Watch: Dir/Any] [d/l] |
|
Thanks for all code & explanation.
used map from "AppleFritter".
| [reply] [Watch: Dir/Any] |
Re: Concise foreach expression
by davido (Cardinal) on Aug 29, 2014 at 15:25 UTC
|
m/test$/ && print "$path_name\n" for @names;
| [reply] [Watch: Dir/Any] [d/l] |
Re: Concise foreach expression
by Anonymous Monk on Aug 29, 2014 at 17:40 UTC
|
The original snippet works fine, and therefore should require no attention from you. Rewriting it to use different constructs probably won't "optimize" it at all ... and is likely (as you saw) to make it stop working altogether and/or to become much more fragile. You are, if I may politely say, wasting your time. | [reply] [Watch: Dir/Any] |
Re: Concise foreach expression
by VincentK (Beadle) on Aug 29, 2014 at 17:34 UTC
|
Hello. I see this one is pretty much answered, but here is my two cents.
use strict;
use warnings;
my @names = ('ABC','123test','DEF','Gibberishafdaf','Moretest','Gibber
+ishafdaf');
($_ =~ /test$/) ? print "[$_] Pattern found\n": print "[$_] Pattern NO
+T found\n" , for(@names);
| [reply] [Watch: Dir/Any] [d/l] |