Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Pulling pairs of values from an array

14 views
Skip to first unread message

RedGrittyBrick

unread,
Dec 17, 2010, 6:59:38 AM12/17/10
to
Consider

#!/usr/bin/perl
use strict;
use warnings;

while(<DATA>) {
my($t1,$t2,$value);
($t1,$t2)=qw(A P); $value = $1 if /^$t1.*$t2=(.)/;
($t1,$t2)=qw(B Q); $value = $1 if /^$t1.*$t2=(.)/;
($t1,$t2)=qw(C R); $value = $1 if /^$t1.*$t2=(.)/;
print "$value\n";
}

__DATA__
A P=1 Q=2 R=3
B P=8 Q=2 R=7
C Q=2 P=1 R=3

I'd like to replace the repetition with an elegant loop over pairs of
$t1,$t2 values stored in an array (or other structure) like one of

my @pairs = qw (A,P B,Q C,R);
my @pairs = qw (A P B Q C R);

I've not had much success with a brief attempt at combining `while`,
`split` and `unshift`.

What concise, elegant solution am I missing?


(Also posted to stackoverflow.com, let me know if you object. I'll post
a combined summary of answers to both fora as penance)

--
RGB

RedGrittyBrick

unread,
Dec 17, 2010, 7:48:27 AM12/17/10
to

In
<http://stackoverflow.com/questions/4470189/perl-pulling-pairs-of-values-from-an-array/4470453#4470453>
Sorpigal suggested

#!/usr/bin/perl
use strict;
use warnings;

my %pairs = qw/A P B Q C R/;

foreach my $data (<DATA>) {
while(my($t1, $t2) = each(%pairs)){
$data =~ /^$t1.*$t2=(.)/ && print "$1\n";
}
}

Which I like. (YMMV)

--
RGB

Tad McClellan

unread,
Dec 17, 2010, 8:59:27 AM12/17/10
to
RedGrittyBrick <RedGrit...@spamweary.invalid> wrote:

> foreach my $data (<DATA>) {

> Which I like. (YMMV)


You should change your mileage so that you don't load the whole
file into memory...

while (my $data = <DATA>) {


--
Tad McClellan
email: perl -le "print scalar reverse qq/moc.liamg\100cm.j.dat/"
The above message is a Usenet post.
I don't recall having given anyone permission to use it on a Web site.

Tad McClellan

unread,
Dec 17, 2010, 9:01:22 AM12/17/10
to
RedGrittyBrick <RedGrit...@spamweary.invalid> wrote:
> Consider
>
> #!/usr/bin/perl
> use strict;
> use warnings;
>
> while(<DATA>) {
> my($t1,$t2,$value);
> ($t1,$t2)=qw(A P); $value = $1 if /^$t1.*$t2=(.)/;
> ($t1,$t2)=qw(B Q); $value = $1 if /^$t1.*$t2=(.)/;
> ($t1,$t2)=qw(C R); $value = $1 if /^$t1.*$t2=(.)/;
> print "$value\n";
> }
>
> __DATA__
> A P=1 Q=2 R=3
> B P=8 Q=2 R=7
> C Q=2 P=1 R=3


That data looks like an HoH to me...


> I'd like to replace the repetition with an elegant loop over pairs of
> $t1,$t2 values stored in an array (or other structure) like one of
>
> my @pairs = qw (A,P B,Q C,R);
> my @pairs = qw (A P B Q C R);

my %pairs = qw/A P B Q C R/;

while (<DATA>) {
my($type, %values) = split /[\s=]/;
print "$values{$pairs{$type}}\n";

RedGrittyBrick

unread,
Dec 17, 2010, 10:29:51 AM12/17/10
to

Thanks. The inventiveness of clpm contributors is a great source of
inspiration.

A Sinan Ünür posted four solutions with some commentary in
<http://stackoverflow.com/questions/4470189/perl-pulling-pairs-of-values-from-an-array/4470720#4470720>.
I'm not sure I can summarise it adequately so I'll just post the URL
here rather than paste it all in verbatim.

--
RGB

s...@netherlands.com

unread,
Dec 17, 2010, 12:29:31 PM12/17/10
to

You don't have to check all the pairs.
You can just get the value with a single if statement
per line of data. Its must faster this way.

Either of these will work (and there is validation so warnings
are not emitted) :

/^(\S+)/g && exists $pairs{$1} && /\G.*$pairs{$1}=(\S+)/
/^(\S+)(??{exists $pairs{$1} ? ".*$pairs{$1}=" : "(*FAIL)"})(\S+)/

-sln

-----------------------------
use strict;
use warnings;

my %pairs = qw/A P B Q C R/;

while ( <DATA> )
{
if (/^(\S+)/g && exists $pairs{$1} && /\G.*$pairs{$1}=(\S+)/) {
print $1,"\n";
}
}
__DATA__

A P=1 Q=2 R=3
B P=8 Q=2 R=7
C Q=2 P=1 R=3


Optional, uses extended regex (??{..}):
while ( <DATA> )
{
if (/^(\S+)(??{exists $pairs{$1} ? ".*$pairs{$1}=" : "(*FAIL)"})(\S+)/) {
print $2,"\n";
}
}

0 new messages