Функция Perl Map - PullRequest
       1

Функция Perl Map

2 голосов
/ 26 июня 2010

Я новичок в функциях map и grep и пытаюсь сделать существующий скрипт более лаконичным.

Я могу "grep" @tracknames успешно, но у меня проблема с "map". Я хочу, чтобы @trackartist возвращал значение true, если в строке найдено два последовательных символа "-", и принимает значение $ 1, в противном случае - значение false, но он возвращает всю строку, если не выполнено верхнее условие. Что я делаю не так?

my @tracknames = grep /^\d\d\..*?(\.(?:flac|wv))$/, <*.*>;
my @trackartist = map { s/^\d\d\.\s(.*?)\s--.*?\.(?:flac|wv)$/$1/; $_; } <*.*>;

Sample of files
01. some track artist 1 -- some track name 1.(flac or wv)
02. some track artist 2 -- some track name 2.(flac or wv)
03. some track artist 3 -- some track name 3.(flac or wv)
etc.

Ответы [ 2 ]

6 голосов
/ 26 июня 2010

Помните, что grep для фильтрации списка, а map для преобразования списка.Прямо сейчас ваш оператор map возвращает $_ для каждого элемента в списке.Если $_ соответствует шаблону в вашей замене, он будет изменен и заменен первым соответствием.В противном случае он не изменяется и возвращается исходный $_.

Похоже, вы хотите отфильтровать элементы, которые не соответствуют шаблону.Одним из способов было бы объединить карту и grep:

my @trackartist = map { s/^\d\d\.\s(.*?)\s--.*?\.(?:flac|wv)$/$1/; $_; }
                  grep { /^\d\d\.\s(.*?)\s--.*?\.(?:flac|wv)$/ } <*.*>;

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

my @trackartist = map { /^\d\d\.\s(.*?)\s--.*?\.(?:flac|wv)$/ ? $1 : ( ) } <*.*>

При этом используется троичный условный оператор (?:) для проверкирегулярное выражение совпадает (возвращая истинное значение).Если это так, $1 возвращается из блока map, если нет, возвращается пустой список ( ), который ничего не добавляет к списку, являющемуся результатом map.

.Обратите внимание, что вы можете захотеть использовать функцию glob вместо <>, что имеет некоторые недостатки.

2 голосов
/ 27 июня 2010

Мне нравится map и grep так же, как следующему парню, но ваша задача кажется более подходящей для подхода анализа "разделяй и властвуй".Я говорю это потому, что ваши комментарии предполагают, что ваш интерес к map ведет вас по дороге, где вы получите модель данных, состоящую из параллельных массивов - @tracks, @artists и т. Д.часто трудно поддерживать в долгосрочной перспективе.Вот эскиз того, что я имею в виду:

my @tracks;

while (my $file_name = <DATA>){ # You'll use glob() or <*.*>
    # Filter out unwanted files.
    my ($num, $artist_title, $ext) = $file_name =~ /
        ^ (\d\d) \. \s*
        (.*)
        \. (flac|wv) $
    /x;
    next unless $ext;

    # Try to parse the artist and title. Adjust as needed.
    my ($artist, $title) = split /\s+--\s+/, $artist_title, 2;
    ($artist, $title) = ('UNKNOWN', $artist) unless $title;

    # Store all info as a hash ref. No need for parallel arrays.
    push @tracks, {
        file_name  => $file_name,
        ext        => $ext,
        artist     => $artist,
        title      => $title,
    };
}

__DATA__
01. Perl Jam -- Open or die.wv
02. Perl Jam -- Map to nowhere.flac
03. Perl Jam -- What the #$@!?.wv
04. Perl Jam -- Regex blues.wv
05. Perl Jam -- Use my package, baby.wv
06. Perl Jam -- No warnings.wv
07. Perl Jam -- Laziness ISA virtue.wv
08. Guido and the Pythons -- Home on the xrange.flac
09. Guido and the Pythons -- You gotta keep em generated.flac
10. StackOverflow medley.wv
foo.txt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...