Как идиоматический способ в Perl определить, соответствует ли строковая переменная строке в списке? - PullRequest
7 голосов
/ 01 февраля 2011

Часть спецификации гласит: «Некоторые имена являются особыми, например, Хьюи, Дьюи, Луис и Дональд. Другие имена могут добавляться в течение жизненного цикла проекта в произвольные моменты времени. Когда вы вводите одно из этих имен, играйте в кряк.wav. "

Я мог бы написать ...

while (<>) {
    if ($_ =~ /Hughie|Dewey|Louis/) {
        quack() ;
    }
    elsif ($_ =~ /Donald/ {
        quack() ;
        you_re_fired_apprentice() ; # Easter egg don't tell QA
    }
}

... но, несмотря на то, что он не облагается налогом, он выглядит WTF-y: Где бинарный поиск?Что если бы произошло внезапное колоссальное увеличение числа имен уток?Это не масштабировалось бы вообще!

Я мог бы создать пустые файлы с использованием этих имен во временном каталоге, а затем использовать API «файл существует», но это кажется окольным, и я должен был быть уверен, что они былиудалено в конце.

Конечно, есть лучший способ?

Ответы [ 6 ]

7 голосов
/ 01 февраля 2011

В качестве альтернативы, вы можете использовать интеллектуальное сопоставление

my @ducks = qw(Hughie Dewey Louis);
my $name = 'Dewey';

say 'smart match' if $name ~~ @ducks;

Это то, что используется операторами переключения , поэтому вы можете написать

given ($name) {
    when (@ducks) {
        quack();
    }
    when ('Donald') {
        quack();
        you_re_fired_apprentice(); # Easter egg don't tell QA
    }
}
7 голосов
/ 01 февраля 2011

Вы могли бы написать это, но вы должны написать это:

my %ducks = map {$_ => 1} qw(Hughie Dewey Louis);

while (<>) {
    if ($ducks{$_}) {
        quack() ;
    }
    elsif ($_ eq 'Donald') {
        quack() ;
        you_re_fired_apprentice() ; # Easter egg don't tell QA
    }
}

Создание хеша занимает немного времени, но не более O(n).Поиск с хешем равен O(1), поэтому он намного эффективнее последовательного поиска (с помощью grep или регулярного выражения с чередованием), если вы будете проверять наличие более одного или двух элементов.

Кстати, регулярное выражение, которое у вас есть, будет соответствовать словам в любом месте строки поиска.Вам нужно добавить начальный и конечный якоря, если вы хотите точное совпадение.

4 голосов
/ 01 февраля 2011

Как уже упоминалось, хэши - это путь для этого.Вот как ООП выглядел до ООП.

use strict;
use warnings;

my %duck_action = (
  Donald => sub {quack(); you_re_fired_apprentice()},
  Hughie => sub {quack()},
  Dewie  => sub {quack()},
  Louis  => sub {quack()},
);

for my $duck (qw( Hughie Dewie Donald Louis Porkie )) {
    print "$duck: ";
    my $action = $duck_action{$duck} || &no_such_duck;
    $action->();
}

sub quack {
    print "Quack!\n";
}

sub you_re_fired_apprentice {
    print "You're fired!\n";
}

sub no_such_duck {
    print "No such duck!\n";
}
3 голосов
/ 01 февраля 2011

Вы можете использовать Perl Hash .См. Также Как я могу представить наборы в Perl? и Представлять наборы в Perl .

Использование хэшей для реализации набора не совсем красиво, но это должно быть быстро .

2 голосов
/ 01 февраля 2011

Чтобы найти строку в списке, вы также можете использовать any в List :: MoreUtils

use List::MoreUtils qw(any);

my @ducks = qw(Hughie Dewey Louis);
my $name = 'Dewey';

say 'any' if any {$name eq $_} @ducks;
1 голос
/ 01 февраля 2011

Если вы привязаны к использованию массива, а не хеша, вы можете использовать функцию perl grep для поиска в массиве строки.

@specialnames = qw(Hughie Dewey Louis);
while (my $value = <>) {
    if (grep {$value eq $_}, @specialnames) {
        quack() ;
    }
    elsif ($_ =~ /Donald/ {
        quack() ;
        you_re_fired_apprentice() ; # Easter egg don't tell QA
    }
}

Это масштабируется намного хуже, чем хеш, и может даже масштабироваться хуже, чем копирование массива в хэш и затем поиск по хешу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...