2010-10-29 17 views
7

Jestem nowicjuszką perl. Mam kod, w którym zmienna jest ładowana z kilkoma wartościami podczas pętli foreach. Co chcę zrobić, to wykonać operację na tej zmiennej tylko wtedy, gdy jest ona w tej tablicy. Jaki jest najskuteczniejszy sposób, aby zrobić to w perlu, ponieważ dane, nad którymi pracuję, są bardzo duże.Perl: znajdź, czy wartość zmiennej pasuje do tej w tablicy

Prostym przykładem jest moje pytanie, że mam tablicę owoców Chcę

@fruits_i_like = qw (mango banana apple); 

Ale mam zmienną $ owoców w pętli foreach, która otrzyma nazwę owoców z pliku danych, które ma wszystkie rodzaje owoców. Jak wybrałbym tylko te przypadki $ fruit, które są w mojej tablicy @fruits_i_like?

+1

Jak duży jest "duży"? – Zaid

+0

również plik, który muszę przeczytać, to około 50 MB. – sfactor

+0

@sfactor: Nie jest tak źle. – Zaid

Odpowiedz

10

Można użyć skrótu takiego:

my %h = map {$_ => 1 } @fruits_i_like; 
if (exists $h{$this_fruit}) { 
    # do stuff 
} 

Tutaj jest punktem odniesienia, który porównać ten sposób vs mfontani rozwiązania

#!/usr/bin/perl 
use warnings; 
use strict; 
use Benchmark qw(:all); 

my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
my %h = map {$_ => 1 } @fruits_i_like; 
my $count = -3; 
my $r = cmpthese($count, { 
    'grep' => sub { 
     if (scalar grep $this_fruit eq $_, @fruits_i_like) { 
      # do stuff 
     } 
    }, 
    'hash' => sub { 
     if (exists $h{$this_fruit}) { 
      # do stuff 
     } 
    }, 
}); 

Wyjście:

  Rate grep hash 
grep 1074911/s -- -76% 
hash 4392945/s 309% -- 
+1

Zmień 'sub {}' na 'q {}' i ponownie uruchom ten test porównawczy. Obciążenie wywołania podprogramu może zbytnio zmienić liczbę. – tchrist

+3

Jeśli utworzysz% h tylko w tym celu, czy nie powinno to być częścią testu porównawczego? –

+3

@ Øyvind Skaar: Nie sądzę, ponieważ OP chce wielokrotnie dopasowywać owoce. % h jest tworzone tylko raz i używane wielokrotnie.Różni się od rozwiązania grep, w którym grep jest wykonywany dla każdego innego owocu. – Toto

11

Perl 5.10 lub nowszy?

use strict; 
use warnings; 
use 5.10.0; 
my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
if ($this_fruit ~~ \@fruits_i_like) { 
    say "yummy, I like $this_fruit!"; 
} 

Przed 5.10:

use strict; 
use warnings; 
my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
if (scalar grep $this_fruit eq $_, @fruits_i_like) { 
    print "yummy, I like $this_fruit!\n"; 
} 

Minusem jest to, że cały tablica jest analizowany przez znaleźć mecze. To może nie być najlepsza opcja, w takim przypadku możesz użyć wartości List::MoreUtils 'any(), która zwraca wartość true, gdy pasuje do wartości i nie przechodzi dalej przez tablicę.

use strict; 
use warnings; 
use List::MoreUtils qw/any/; 
my @fruits_i_like = qw/mango banana apple/; 
my $this_fruit = 'banana'; 
if (any { $this_fruit eq $_ } @fruits_i_like) { 
    print "yummy, I like $this_fruit!\n"; 
} 

Happy hacking!

9

Jest to skutecznie problem z wyszukiwaniem. Szybciej byłoby sprawdzić wartości @fruits_i_like w haszdzie, takim jak %fruits_i_like (który jest O (1) w stosunku do O (n) tablicy).

Konwersja tablicę do mieszania stosując następującą operację:

open my $data, '<', 'someBigDataFile.dat' or die "Unable to open file: $!"; 

my %wantedFruits; 
@wantedFruits{@fruits_i_like} =(); # All fruits_i_like entries are now keys 

while (my $fruit = <$data>) {  # Iterates over data file line-by-line 

    next unless exists $wantedFruits{$fruit}; # Go to next entry unless wanted 

    # ... code will reach this point only if you have your wanted fruit 
} 
Powiązane problemy