Каково различие между итерацией по файлу с foreach или в то время как в Perl?

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

32
задан Nathan Fellman 25 February 2009 в 21:19
поделиться

8 ответов

В большинстве целей Вы, вероятно, не заметите различия. Однако foreach чтения каждая строка в список ( не массив ) перед прохождением через него линию за линией, тогда как while чтения одна строка за один раз. Как foreach будет использовать больше памяти и требовать времени обработки заранее, обычно рекомендуется использовать while для итерации через строки файла.

РЕДАКТИРОВАНИЕ (через Schwern): foreach цикл эквивалентен этому:

my @lines = <$fh>;
for my $line (@lines) {
    ...
}

неудачно, что Perl не оптимизирует этот особый случай, как это делает с оператором диапазона (1..10).

, Например, если я считал/usr/share/dict/words с for цикл и while цикл и сделал, чтобы они спали, когда они сделаны, я могу использовать ps для наблюдения, сколько памяти процесс использует. Как управление я включал программу, которая открывает файл, но ничего не делает с ним.

USER       PID %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern  73019   0.0  1.6   625552  33688 s000  S     2:47PM   0:00.24 perl -wle open my $fh, shift; for(<$fh>) { 1 } print "Done";  sleep 999 /usr/share/dict/words
schwern  73018   0.0  0.1   601096   1236 s000  S     2:46PM   0:00.09 perl -wle open my $fh, shift; while(<$fh>) { 1 } print "Done";  sleep 999 /usr/share/dict/words
schwern  73081   0.0  0.1   601096   1168 s000  S     2:55PM   0:00.00 perl -wle open my $fh, shift; print "Done";  sleep 999 /usr/share/dict/words

for программа использует почти 32 megs реальной памяти (RSS столбец) для хранения содержания моих 2.4 meg/usr/share/dict/words. while цикл только хранит одну строку в трудоемком просто 70k для буферизации строки.

37
ответ дан 27 November 2019 в 20:19
поделиться

В дополнение к предыдущим ответам другое преимущество использования while - то, что можно использовать $. переменная. Это - текущий номер строки последнего дескриптора файла, к которому получают доступ (см. perldoc perlvar ).

while ( my $line = <FILE> ) {
    if ( $line =~ /some_target/ ) {
        print "Found some_target at line $.\n";
    }
}
10
ответ дан 27 November 2019 в 20:19
поделиться

В скалярном контексте (т.е. while) <FILE> возвраты каждая строка в свою очередь.

В контексте списка (т.е. foreach) <FILE> возвращает список, состоящий из каждой строки из файла.

Необходимо использовать while создать.

См. perlop - Операторы ввода-вывода для больше.

Править: j_random_hacker справедливо говорит это

while (<FILE>) { … }

топчет $_ в то время как foreach не делает (foreach, локализует $_ сначала). Конечно, это - самое важное поведенческое различие!

19
ответ дан 27 November 2019 в 20:19
поделиться

Обновление: j случайный хакер указывает в комментарии что особые случаи Perl тест ошибочности в некоторое время цикле при чтении из дескриптора файла. Я только что проверил, что чтение ложного значения не завершит цикл - по крайней мере, на современном жемчуге. Извините за регулирование Вас неправильно. После 15 лет записи Perl я - все еще новичок.;)

Все выше правы: используйте while цикл, потому что это будет большей эффективной памятью и даст Вам больше контроля.

А забавная вещь о том while цикл, хотя то, что это выходит, когда чтение является ложью. Обычно это будет концом файла, но что, если он возвратит пустую строку или 0? Ой! Из Вашей программы просто выходят слишком скоро. Это может произойти на любом дескрипторе файла, если последняя строка в файле не имеет новой строки. Это может также произойти с пользовательскими объектами файла, которые имеют метод чтения, который не рассматривает новые строки тот же путь как регулярные объекты файла Perl.

Вот то, как зафиксировать его. Проверьте на неопределенное чтение значения, которое указывает на конец файла:

while (defined(my $line = <FILE>)) {
    print $line;
}

foreach цикл не имеет этой проблемы между прочим и корректен даже при том, что неэффективный.

2
ответ дан 27 November 2019 в 20:19
поделиться

j_random_hacker упомянул это в комментариях к этому ответу , но фактически не поместил его в ответ само по себе, хотя это еще одно отличие, о котором стоит упомянуть.

Разница в том, что while () {} перезаписывает $ _ , а foreach (< FILE>) {} локализует его. То есть:

$_ = 100;
while (<FILE>) {
    # $_ gets each line in turn
    # do something with the file
}
print $_; # yes I know that $_ is unneeded here, but 
          # I'm trying to write clear code for the example

распечатает последнюю строку .

Однако

$_ = 100;
foreach(<FILE>) {
    # $_ gets each line in turn
    # do something with the file
}
print $_;

распечатает 100 . Чтобы получить то же самое с while (<

1
ответ дан 27 November 2019 в 20:19
поделиться

Я добавил пример, посвященный этому, в следующее издание Эффективное программирование на Perl .

С помощью while вы можете остановить обработку ФАЙЛА и по-прежнему получать необработанные строки:

 while( <FILE> ) {  # scalar context
      last if ...;
      }
 my $line = <FILE>; # still lines left

Если вы используете foreach , вы потребляете все строки в foreach , даже если вы прекратите их обработку:

 foreach( <FILE> ) { # list context
      last if ...;
      }
 my $line = <FILE>; # no lines left!
3
ответ дан 27 November 2019 в 20:19
поделиться

Вот пример, где foreach не будет работать, но , а выполнит задание

while (<FILE>) {
   $line1 = $_;
   if ($line1 =~ /SOMETHING/) {
      $line2 = <FILE>;
      if (line2 =~ /SOMETHING ELSE/) {
         print "I found SOMETHING and SOMETHING ELSE in consecutive lines\n";
         exit();
      }
   }
}

Вы просто не можете сделать это с помощью foreach , потому что он прочитает весь файл в список перед входом в цикл, и вы не сможете прочитать следующую строку внутри петли. Я уверен, что для этой проблемы найдутся обходные пути даже в foreach (на ум приходит чтение в массив), но определенно предлагает очень простое решение.

Второй пример - это когда вам нужно проанализировать большой (скажем, 3 ГБ) файл на вашем компьютере с оперативной памятью всего 2 ГБ. foreach просто не хватит памяти и произойдет сбой. Я усвоил это на собственном горьком опыте в самом начале моей жизни программирования на Perl.

1
ответ дан 27 November 2019 в 20:19
поделиться

Цикл foreach выполняется быстрее, чем цикл while (который является условным).

0
ответ дан 27 November 2019 в 20:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: