Perl:两个列表中的对元素

时间:2016-11-23 08:12:23

标签: perl

我有两个清单:

my @prefixes = ["abc", "def", "ghi", "jklmn"];
my @strings = ["abc123", "def456", "jklmnopqrst"];

我需要为每个字符串找到正确的前缀,以便“abc123”属于“abc”而“def456”属于“def”而“jklmnopqrst”属于“jklmn”。 所有字符串在@prefixes中都有一个前缀,但并非所有前缀都有匹配的字符串(请参阅“ghi”)。

我有这段代码:

use List::Util qw(first);
...
foreach my $str (@strings) {
    my $prefix = first { $_ eq substr($str, 0, length($_)) } @prefixes;
    print "$prefix\n";
    # do something with $str and $prefix together
}

但它不起作用,我得到Use of uninitialized value $prefix in concatenation (.) or string

怎么了?

更新:所以这很容易解决。我应该使用()而不是[]来初始化我的列表。为了不关闭它,你将如何摆脱foreach声明?

2 个答案:

答案 0 :(得分:3)

您可以从前缀创建正则表达式模式,并使用它来构造哈希:

#!/usr/bin/env perl

use strict;
use warnings;

use YAML::XS;

my @prefixes = qw[abc def ghi jklmn];
my @strings  = qw[abc123 def456 jklmnopqrst];

my ($prefix_re) = map qr/$_/, sprintf(
    '^(?<prefix>%s)',
    join '|', sort { length $b <=> length $a } @prefixes
);

print "$prefix_re\n";

my %matches = map { $_ =~ $prefix_re; ($+{prefix}, $_) } @strings;

print Dump \%matches;

输出:

abc: abc123
def: def456
jklmn: jklmnopqrst

如果多个字符串可以匹配前缀,则可以将前缀映射到匹配字符串列表:

#!/usr/bin/env perl

use strict;
use warnings;

use YAML::XS;

my @prefixes = qw[abc def ghi jklmn];
my @strings  = qw[abc123 def456 def789 jklmnopqrst];

my ($prefix_re) = map qr/$_/, sprintf(
    '^(?<prefix>%s)',
    join '|', sort { length $b <=> length $a } @prefixes
);

print "$prefix_re\n";

my %matches;

for my $str ( @strings ) {
    next unless $str =~ $prefix_re;
    push @{ $matches{ $+{prefix} }}, $str;
}

print Dump \%matches;

输出:

---
abc:
- abc123
def:
- def456
- def789
jklmn:
- jklmnopqrst

答案 1 :(得分:2)

但是,代替foreach您可以使用map,代码的可读性会大大降低。

#!/usr/bin/env perl

use strict;
use warnings;

use List::Util qw/ first /;

my @prefixes = ("abc", "def", "ghi", "jklmn");
my @strings = ("abc123", "def456", "jklmnopqrst");

# foreach my $str ( @strings ) {
#   my $prefix = first { $_ eq substr( $str, 0, length( $_ )) } @prefixes;
#   print $prefix, "\n";
# }

my @found  = map { my $str = $_; first { $_ eq substr( $str, 0, length( $_ ))} @prefixes } @strings;

print join("\n", @found), "\n";