2016-11-23 5 views
1

Ich habe zwei Listen:Perl: Paar Elemente in zwei Listen

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

Ich brauche die richtige Vorsilbe für jede Saite zu finden, so dass „abc123“ gehört „abc“ und „def456“ gehört „def "und" jklmnopqrst "gehört zu" jklmn ". Alle Zeichenfolgen haben ein Präfix in @prefixes, aber nicht alle Präfixe haben eine übereinstimmende Zeichenfolge (siehe "ghi").

Ich habe diesen Code:

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 
} 

Aber es funktioniert nicht, ich bin immer Use of uninitialized value $prefix in concatenation (.) or string

Was ist los?

UPDATE: So war es eine einfache Lösung. Ich hätte meine Listen mit() und nicht mit [] initialisieren sollen. Um das noch nicht zu schließen, wie würden Sie die foreach Anweisung loswerden?

+0

Ok, ich bin dumm. Ich hätte meine Arrays mit() anstelle von [] initialisieren sollen. – papaiatis

+0

Mit 'map' - aber dann haben Sie nicht so viel Flexibilität, um innen zu verarbeiten, wie Sie es mit' foreach' machen. – zdim

Antwort

3

Sie einen RegexMuster aus den Präfixen erstellen können, und dass ein Hash zu konstruieren verwenden:

#!/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; 

Ausgang:

abc: abc123 
def: def456 
jklmn: jklmnopqrst

Wenn mehrere Strings einen Präfix übereinstimmen, können Sie Kartenpräfixe zu Listen übereinstimmender Zeichenfolgen:

#!/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; 

Ausgabe:

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

Das ist eine andere nette Lösung! Vielen Dank! – papaiatis

+0

Froh, dass es geholfen hat. Denken Sie daran, dass Sie in Bezug auf den Speicherbedarf und die Leistung möglicherweise besser dran sind, wenn Sie nur Übereinstimmungen, Verarbeitungen und Weiterschaltungen vornehmen, anstatt Übereinstimmungen zu speichern. –

2

Anstelle der foreach könnten Sie map verwenden, der Code wird jedoch erheblich weniger lesbar.

#!/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"; 
Verwandte Themen