2016-11-23 64 views
1

元素对我有两份名单:的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

有什么不对?

UPDATE:所以这是一个简单的修复。我应该使用()而不是[]初始化我的列表。为了不关闭这个,你将如何摆脱foreach声明?

+0

好的,我很笨。我应该用()而不是[]来初始化我的数组。 – papaiatis

+0

使用'map' - 但是你没有像使用foreach一样处理内部的灵活性。 – zdim

回答

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

这是另一个不错的解决方案!万分感谢! – papaiatis

+0

很高兴帮助。请记住,如果您只匹配,处理并继续前进,而不是存储匹配项,则在内存占用和性能方面可能会更好。 –

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";