2016-11-23 19 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";