Re: Splitting array into two with a regex
by Fletch (Bishop) on Nov 08, 2005 at 14:46 UTC
|
my( @ok, @no );
push @{ $_->name =~ /\d{2}$/ ? \@ok : \@no }, $_ for @{ $rec->vals }
Update: Heh, I was going to mention Ruby as well.
| [reply] [d/l] |
|
|
| [reply] |
|
|
$rec->vals we can presume is some OO code, but's it's not defined by the OP.
What Fletch is doing here is testing the value returned by $rec->val, and according to the result, returning a reference to one of the two arrays. This whole things is wrapped in a @{ } which will deference the array ref returned in the first instance, which he can then push the value to.
Here's a slightly less complicated version, using the same principal
use strict;
use Data::Dumper;
my @numbers = (1,2,3,45,6,76,8,5,7,8);
my(@odd, @even);
foreach my $number (@numbers) {
push @{ is_odd($number) ? \@odd : \@even}, $number;
}
print Dumper(\@odd, \@even);
sub is_odd {$_[0] % 2}
---
my name's not Keith, and I'm not reasonable.
| [reply] [d/l] |
|
|
Could you explain what does it mean @{$rec->vals}.
@{$rec->vals}
can be written as
@{$rec->vals()}
or as
my $aref = $rec->vals();
@{$aref}
Is it array ref?
$rec->vals() is an expression that returns an array reference.
@{$rec->vals()} is an expression that returns an array lvalue (which means it can be used like a real array).
Update: Fixed problem noted by merlyn.
| [reply] [d/l] [select] |
|
|
|
|
|
Re: Splitting array into two with a regex
by dragonchild (Archbishop) on Nov 08, 2005 at 14:46 UTC
|
This is what Ruby's Array.partition() is for. You can replicate it in Perl pretty easily.
sub partition (&@) {
my ($condition, @array) = @_;
my (@true, @false);
foreach (@array) {
if ( $condition->($_) ) {
push @true, $_;
}
else {
push @false, $_;
}
}
return \@true, \@false;
}
my ($ok, $no) = partition { $_[0]->name =~ m/[0-9]{2}$/ } @{ $rec->val
+s };
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] [d/l] |
|
|
sub partition (&@) {
my ($condition, @array) = @_;
my (@true, @false);
foreach (@array) {
if ( $condition->() ) {
push @true, $_;
}
else {
push @false, $_;
}
}
return \@true, \@false;
}
my ($ok, $no) = partition { $_->name =~ m/[0-9]{2}$/ } @{ $rec->vals }
+;
In what is likely to be a common case, where the array is an array of strings rather than object references, that partition block becomes even more trivial. I've taken to this idiom in the last few months just because of the way it simplifies the callbacks. That it is probably faster (no parameters to pass around) actually has had no bearing on whether I use this or not (may shave off a second or two over three hours - not a concern). | [reply] [d/l] |
|
|
sub partition (&$@)
{
my $condition = shift;
my $receivers_ar = shift;
push @{ $receivers_ar->[ &$condition ] }, $_ for @_;
@$receivers_ar
}
# Example 1:
my( @good, @bad );
partition { /u/ ? 1 : 0 } [ \@good, \@bad ], qw( foo bar quux );
print "good=@good\n";
print "bad=@bad\n";
# Example 2:
my @r = partition { $_ % 3 } [ [], [], [], ], 0 .. 12;
for my $i ( 0 .. $#r )
{
print "$i = @{$r[$i]}\n";
}
We're building the house of the future together.
| [reply] [d/l] |
|
|
|
|
Re: Splitting array into two with a regex
by Roy Johnson (Monsignor) on Nov 08, 2005 at 15:54 UTC
|
Another Way To Do It, with a single grep (and a little trick):
my @no;
my @ok = grep { $_->name =~ m/[0-9][0-9]$/ or !push(@no, $_) }@{ $rec-
+>vals };
Caution: Contents may have been coded under pressure.
| [reply] [d/l] |
|
|
well, if you're going to do that, you might as well stick it on one line...
my (@ok, @no) = grep { $_->name =~ m/[0-9][0-9]$/ or !push(@no, $_) }@
+{ $rec->vals };
... hmmmm, perhaps not :)
Update: Definitely not. As Roy Johnson kindly pointed out, @no will not exist in time to be pushed to in the grep.
---
my name's not Keith, and I'm not reasonable.
| [reply] [d/l] |
Re: Splitting array into two with a regex
by GrandFather (Saint) on Nov 08, 2005 at 20:24 UTC
|
And the benchmark:
Prints:
Rate Tanktalus OP JDPorter Roy Fletch
+ GF
Tanktalus 39861/s -- -14% -23% -43% -44%
+ -57%
OP 46391/s 16% -- -11% -34% -35%
+ -50%
JDPorter 51919/s 30% 12% -- -26% -27%
+ -44%
Roy 70510/s 77% 52% 36% -- -1%
+ -23%
Fletch 71157/s 79% 53% 37% 1% --
+ -23%
GF 91995/s 131% 98% 77% 30% 29%
+ --
Update: forgot Roy Johnston's version
Perl is Huffman encoded by design.
| [reply] [d/l] [select] |
Re: Splitting array into two with a regex
by blahblahblah (Priest) on Nov 09, 2005 at 00:26 UTC
|
There's a module on CPAN that does this in a general way, even letting you split the list into more than two result lists: List::Part.
-Joe | [reply] |
Re: Splitting array into two with a regex
by GrandFather (Saint) on Nov 08, 2005 at 19:53 UTC
|
(@ok, @no) = ((), ());
map {$_->name =~ /[0-9][0-9]$/ ? push @ok, $_ : push @no, $_} @{$rec->
+vals};
Perl is Huffman encoded by design.
| [reply] [d/l] |