Re: from array to hash with grep
by bart (Canon) on Jun 15, 2006 at 08:04 UTC
|
"You can't make shit up and expect Perl to know what it means, retardo!"... ((in)famous MJD quote)
There must be a logical technical reason to how it should/could work. grep reads a list and checks for which ones the condition evaluates to true. That's all. That doesn't look very useful.
Now you're try this with map, it'll build a list of return values instead. Now what would the value returned from the regexp be? Why, you have capturing parens, map calls the regexp in list context, so it'll return an empty list for no match, and a list of captured values for matches. So
@result = map /\w{3}_(\w)/, @inp;
will put ('A', 'B', 'C') into the array, for your particular input.
If you foreach through that list, you can use each as a hash key, in turn. So this will do what you want:
$inp{$_} = 1 foreach map /\w{3}_(\w)/, @inp;
It looks close to what you made up, but it isn't. Not really.
| [reply] [d/l] [select] |
|
OK, al that makes me understand map and grep better. I just realized that I want it a little bit different, I need a hash with the same keys but the values should be the whole string, so you would get:
$inp{A} = 'abc_A_bla' ;
etc
Is this still possible with map or should I switch to a simpel foreachforeach ( @inp ) {
($key) = $_ =~ /\w{3}_(\w)/ ;
$inp{$key} = $_ ;
}
?
Luca | [reply] [d/l] [select] |
|
@flat = map { /\w{3}_(\w)/ ? ($1, $_) : () } @inp;
It'll create a pair like ("A", "abc_A_bla") for a match, and an empty list for no match.
Assign to the hash, and you get:
%inp = map { /\w{3}_(\w)/ ? ($1, $_) : () } @inp;
| [reply] [d/l] [select] |
|
my @inp = ("abc_A_bla", "abc_B_bla", "abc_C_bla");
my %inp = map { /\w{3}_(\w)/; $1 => $_ } @inp ;
foreach ( keys %inp ) {
print "$_ => $inp{$_}\n";
}
Update: Better to use bart's version which includes checks for when the regex doesn't match.
--
< http://dave.org.uk>
"The first rule of Perl club is you do not talk about
Perl club." -- Chip Salzenberg
| [reply] [d/l] |
Re: from array to hash with grep
by davorg (Chancellor) on Jun 15, 2006 at 08:22 UTC
|
A quick rule of thumb which might help to decide if you want grep or map.
If you have a list and you want to filter that list so that you don't get back all of the items, then you probably want grep.
If you have a list and you want to transform each item in the list in some way then you probably want map.
Generally speaking, given a list with N items, grep returns a list with <= N items and map returns a list with N items[1]
[1] Yes, I know that map can actually return more than N items and even less than N items - but my explaination is true to a first approximation.
--
< http://dave.org.uk>
"The first rule of Perl club is you do not talk about
Perl club." -- Chip Salzenberg
| [reply] |
Re: from array to hash with grep
by sonofason (Sexton) on Jun 15, 2006 at 08:00 UTC
|
Try using map instead:
my %inp = map {/^\w{3}_(\w)/; ($1, 1)} @inp;
| [reply] [d/l] |
Re: from array to hash with grep
by graq (Curate) on Jun 15, 2006 at 08:12 UTC
|
I expect there are plenty of 'use map!' replies before I finish this, but I'll throw my torch light on the subject.
- $inp{$_} = 1 grep ( /\w{3}_(\w)/, @inp ) ;
This is initially syntactically wrong. You have a list and need to iterate over it somehow.
- $inp{$_} = 1 for grep ( /\w{3}_(\w)/, @inp );
However grep returns the line that matched, not what you 'captured' in $1, so you will match all lines with no change.
Hence you need to use map.
- $inp{$_} = 1 for map ( /\w{3}_(\w)/, @inp );
| [reply] [d/l] [select] |
Re: from array to hash with grep
by ioannis (Abbot) on Jun 15, 2006 at 08:19 UTC
|
Since it is fixed-length scanning, we can use pack() and unpack():
my @inp = ("abc_A_bla", "abc_B_bla", "abc_C_bla") ;
print "@{[ keys %{{ unpack '(x4 A A4)*', pack( '(A*)*', @inp) }}]}";
| [reply] [d/l] |
Re: from array to hash with grep
by Moron (Curate) on Jun 15, 2006 at 08:49 UTC
|
At first sight it looked as if a minor modification was necessary, but grep has run through the array and returned a list before the lhs can get at each match variable, preventing them being assigned to keys of %inp (normally you'd use $1 not $_).
map was probably invented for this kind of reason. But the example doesn't really demand it that strongly when the lhs is a hash - 'for' still seems adequate and simple to me:
#!/usr/bin/perl
use strict ;
use warnings ;
my @inp = ("abc_A_bla", "abc_B_bla", "abc_C_bla") ;
my %inp ;
$inp{ $1 } = /\w{3}_(\w)/ || next for @inp;
foreach ( keys %inp ) {
print "Found $_\n" ;
}
| [reply] [d/l] |