考虑
#!/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
我想用优雅的循环代替存储在数组(或其他结构)中的$ t1,$ t2值,如
之一my @pairs = qw (A,P B,Q C,R);
my @pairs = qw (A P B Q C R);
我在简短尝试合并while
,split
和unshift
方面没有取得多大成功。
我错过了什么简洁优雅的解决方案?
P.S。我过去使用过哈希,但发现%h = (A=>'P', B=>'Q', C=>'R')
语法“嘈杂”。扩展到三胞胎,四边形也很难看......
答案 0 :(得分:9)
当哈希+ each
不够好时(因为
use List::MoreUtils q/natatime/;
while(<DATA>) {
my($t1,$t2,$value);
my @pairs = qw(A P B Q C R);
my $it = natatime 2, @pairs;
while (($t1,$t2) = $it->()) {
$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
但是,通常情况下,我只会splice
列出此列任务列表的前几个元素:
while(<DATA>) {
my($t1,$t2,$value);
my @pairs = qw(A P B Q C R);
# could also say @pairs = (A => P, B => Q, C => R);
while (@pairs) {
($t1,$t2) = splice @pairs, 0, 2;
$value = $1 if /^$t1.*$t2=(.)/;
}
print "$value\n";
}
答案 1 :(得分:4)
使用哈希。
my %map = ( A => 'P', B => 'Q', C => 'R' );
while (<DATA>) {
my $re = substr($_, 0, 1) . ".*" . $map{ substr($_, 0, 1) } . "=(.)";
/$re/;
print "$1\n";
}
答案 2 :(得分:4)
除非您能保证第一个坐标始终是唯一的,否则一对的概念更好地表示为两个元素的单个数组。您也可以更容易地将相同的想法扩展到更高维度的元组。
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;
my @tuples = ([qw(A P)], [qw(B Q)], [qw(C R)]);
my $re_tmpl = '^%s.*%s=(.)';
my @re = map qr/$_/, map sprintf($re_tmpl, @$_), @tuples;
while (my $line = <DATA>) {
last unless $line =~ /\S/;
my ($value) = map { $line =~ $_ } @re;
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
但是,使用上面的方法和方法,您执行的匹配操作比必要的多(每行三个而不是一个)。这使得@eugene's answer更有效率。
更通用的解决方案是使用:
#!/usr/bin/perl
use strict; use warnings;
my @tuples = ([qw(A P)], [qw(B Q)], [qw(C R)]);
my $re_tmpl = '^%s.*%s=(.)';
my %re;
@re{ map $_->[0], @tuples } = map qr/$_/,
map sprintf($re_tmpl, @$_),
@tuples;
while (my $line = <DATA>) {
last unless $line =~ /\S/;
my ($value) = $line =~ $re{substr $line, 0, 1};
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
关于这一点的好处是你可以适应尺寸大于2的元组。
此外,既然您正在根据线条的第一个字符选择图案,那么图案本身就会变得更简单:
#!/usr/bin/perl
use strict; use warnings;
my @tuples = ([qw(A P)], [qw(B Q)], [qw(C R)]);
my $re_tmpl = '%s=(.)';
my %re;
@re{ map $_->[0], @tuples } = map qr/$_/,
map sprintf($re_tmpl, $_->[1]),
@tuples;
while (my $line = <DATA>) {
last unless $line =~ /\S/;
my ($value) = $line =~ $re{substr $line, 0, 1};
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
一个更简单的替代方案(需要捕获所有x=y
)是:
#!/usr/bin/perl
use strict; use warnings;
my %pairs = qw(A P B Q C R);
my $re = qr/([A-Z])=([0-9])/;
while (my $line = <DATA>) {
last unless $line =~ /\S/;
my $type = substr $line, 0, 1;
my $value = { $line =~ /$re/g }->{ $pairs{$type} };
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
最后一个也可以轻松从一行中提取多个值:
#!/usr/bin/perl
use strict; use warnings;
my %tuples = (A => [qw(P Q)], B => [qw(Q R)], C => [qw(P R)]);
my $re = qr/([A-Z])=([0-9])/;
while (my $line = <DATA>) {
last unless $line =~ /\S/;
my $type = substr $line, 0, 1;
my @values = @{ { $line =~ /$re/g } }{ @{ $tuples{$type} } };
print "@values\n";
}
__DATA__
A P=1 Q=2 R=3
B P=8 Q=2 R=7
C Q=2 P=1 R=3
答案 3 :(得分:3)
扩展我的评论。
#!/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";
}
}
答案 4 :(得分:1)
Elsewhere,Tad McLellan观察到数据看起来像是HoH并建议:
my %pairs = qw/A P B Q C R/;
while (<DATA>) {
my($type, %values) = split /[\s=]/;
print "$values{$pairs{$type}}\n";
}