Каков наилучший способ выполнить итерацию от элемента n до конца массива?

StackOverflow https://stackoverflow.com/questions/1520900

Вопрос

Проблема в том, что у меня есть n аргументов командной строки.Их всегда будет как минимум 2, однако максимальное число не ограничено.Первый аргумент задает режим работы, а второй - файл для обработки.С 3-го по n-е - это то, что нужно сделать с файлом (чего может и не быть, поскольку пользователь может просто захотеть очистить файл, что будет сделано, если вы просто передадите ему 2 аргумента).

Я смотрю на доступные мне методы в Perl для работы с массивами, но я не уверен, что такое "Perlish" способ итерации от элемента 3 до конца моего массива.

Некоторые варианты, которые я видел:

  • Просматривайте массив с конца, пока я не найду элемент, который не начинается с "-" (поскольку путь к файлу не начинается с "-", хотя я полагаю, что это возможно, что может вызвать проблемы).
  • Дважды сдвиньте массив, чтобы удалить первые два элемента.Все, что у меня осталось, я могу просто повторить, если его размер равен хотя бы 1.

Мне нравится второй вариант, но я не знаю, подходит ли он по-английски.И поскольку я пытаюсь выучить Perl, я мог бы с таким же успехом научиться правильно делать что-то на Perl.

Это было полезно?

Решение

Помимо использования модуля Getopt, как писал Синан, я бы, вероятно, выбрал:

my ( $operation, $file, @things ) = @ARGV;

И тогда вы сможете:

for my $thing_to_do ( @things ) {
...
}

Другие советы

ИМХО, лучшим способом достижения того, что вам нужно, было бы использовать один из Модули Getopt на CPAN.

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

die "Must provide filename and operation\n" unless @ARGV >= 2;

my $op = shift @ARGV;
my $file = shift @ARGV;

if ( @ARGV ) {
    # handle the other arguments;
}

Я бы так и сделал весьма рекомендую использовать Getopt::Длинный для синтаксического анализа аргументов командной строки.Это стандартный модуль, он работает потрясающе и с легкостью выполняет именно то, что вы пытаетесь сделать.

use strict;
use warnings;
use Getopt::Long;

my $first_option = undef;
my $second_option = undef;

GetOptions ('first-option=s' => \$first_option, 
            'second-option=s' => \$second_option);

die "Didn't pass in first-option, must be xxxyyyzzz."
    if ! defined $first_option;
die "Didn't pass in second-option, must be aaabbbccc."
    if ! defined $second_option;

foreach my $arg (@ARGV) {
    ...
}

Это позволяет вам иметь длинное название опции, автоматически вводить информацию в переменные для вас и позволяет вам протестировать ее.Это даже позволяет вам добавлять дополнительные команды позже, без необходимости выполнять какой-либо дополнительный синтаксический анализ аргументов, например, добавлять опцию "версия" или "справка":

# adding these to the above example...
my $VERSION = '1.000';
sub print_help { ... }

# ...and replacing the previous GetOptions with this...
GetOptions ('first-option=s' => \$first_option, 
            'second-option=s' => \$second_option)
            'version' => sub { print "Running version $VERSION"; exit 1 },
            'help' => sub { print_help(); exit 2 } );

Затем вы можете вызвать его в командной строке, используя -, --, первая буква или весь вариант целиком, и GetOptions выяснит все это за тебя.Это делает вашу программу более надежной и понятной;можно сказать, это более "угадываемо".Самое приятное, что вам никогда не придется менять свой код, который обрабатывает @ARGV, потому что GetOptions я позабочусь обо всех этих настройках за вас.

Самый стандартный способ делать что-либо в Perl - это через CPAN.

Так что моим первым выбором было бы Getopt::Длинный.Существует также учебное пособие по DevShed: Обработка параметров командной строки с помощью Perl

Вы можете использовать нарезать чтобы извлечь 2-й.к последним элементам, например:

[dsm@localhost:~]$ perl -le 'print join ", ", @ARGV[2..$#ARGV];' 1 2 3 4 5 6 7 8 9 10 00
3, 4, 5, 6, 7, 8, 9, 10, 00
[dsm@localhost:~]$ 

тем не менее, вам, вероятно, следует использовать shift (или даже лучше, GetOpt::Long)

глубокий ответ - это один из хороших путей.

Также нет ничего плохого в вашем втором варианте:

my $op     = shift; # implicit shift from @ARGV
my $file   = shift; 
my @things = @ARGV;

# iterate over @things;

Вы также можете пропустить копирование @ARGV в @things и работайте непосредственно над этим.Однако, если сценарий не очень короткий, очень простой и вряд ли будет усложняться со временем, я бы не стал прибегать к слишком большому количеству сокращений.

Выберете ли вы подход deepesz или этот, во многом зависит от вкуса.

Решение о том, что лучше, на самом деле является вопросом философии.Суть проблемы заключается в том, следует ли вам изменять глобальные переменные, такие как @ARGV.Кто-то сказал бы, что в этом нет ничего особенного, если это делается очень заметным образом.Другие высказались бы за то, чтобы уйти @ARGV нетронутый.

Не обращайте внимания на тех, кто спорит в пользу того или иного варианта из-за проблем со скоростью или памятью.Тот Самый @ARGV большинство оболочек ограничивают массив очень небольшим размером, и поэтому при использовании одного метода поверх другого существенная оптимизация невозможна.

Getopt::Длинный, как уже упоминалось, тоже является отличным выбором.

Пожалуйста, взгляните на MooseX::Getopt потому что это может разжечь ваш аппетит к еще большему количеству вещей Муси!.

Пример MooseX::Getopt:

# getopt.pl

{
    package MyOptions;
    use Moose;
    with 'MooseX::Getopt';

    has oper   => ( is => 'rw', isa => 'Int', documentation => 'op doc stuff' );
    has file   => ( is => 'rw', isa => 'Str', documentation => 'about file' );
    has things => ( is => 'rw', isa => 'ArrayRef', default => sub {[]} );

    no Moose;
}

my $app = MyOptions->new_with_options;

for my $thing (@{ $app->things }) {
    print $app->file, " : ", $thing, "\n";
}

# => file.txt : item1
# => file.txt : item2
# => file.txt : item3

Будет выдавать описанное выше при запуске следующим образом:

perl getopt.pl --операция 1 --файл file.txt --элемент вещей 1 --элемент вещей 2 --элемент вещей 3


Эти типы лосей проверены... ./getopt --oper "not a number" производит:

Value "not a number" invalid for option oper (number expected)

И бесплатно вы всегда получаете список использования ;-)

usage: getopt.pl [long options...]
         --file         bit about file
         --oper         op doc stuff
         --things    

/I3az/

Для более общего случая с любым массивом:

for(my $i=2; $i<@array; $i++) {
    print "$array[$i]\n";
}

Это перебирает массив, начиная с третьего элемента (индекс 2).Очевидно, что в конкретном примере, который вы указали, ответ депеша является самым простым и лучшим.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top