Как найти количество значений в списке Perl? - PullRequest
7 голосов
/ 09 февраля 2010

Количество значений в списке может быть определено только путем перебора его значений или преобразования его в массив. Присвоение его скаляру не вернет количество предметов:

my $n = ('a', 'b', 'c');  # $n = 'c' 

Существует идиома "пустые скобки", которую можно использовать для получения количества элементов:

my $n = () = ('a', 'b', 'c'); # $n = 3

Внутренне ли это эквивалентно

my $n = @{[ 'a', 'b', 'c' ]};

Ответы [ 7 ]

8 голосов
/ 09 февраля 2010

Два элемента, которые вы показали, не эквивалентны. Но они имеют одинаковый конечный результат;

my $n = @{[ 'a', 'b', 'c' ]};

Здесь вы создаете анонимный массив [ 'a', 'b', 'c' ], затем разыменовываете его и берете количество членов. Создание массива предоставляет контекст списка операторам запятой в операторе.

my $n = () = ('a', 'b', 'c');

Здесь мы используем печально известный «оператор козла». Список ('a', 'b', 'c') присваивается пустому списку () = ('a', 'b', 'c');. Результат присвоения списка присваивается $n. Назначение списка возвращает количество элементов в правой части назначения в скалярном контексте (в контексте списка вы получите список значений, назначенных для него).

6 голосов
/ 09 февраля 2010

Это интересная деталь реализации: Создает ли присвоение пустому списку (ненужный) анонимный массив?

Есть два способа ответить на этот вопрос: во-первых, правильный путь: попытаться выяснить, как это может быть обработано в источнике. Существует ли особый случай присвоения пустому списку, вычисляемому в скалярном контексте?

Будучи ленивым и невежественным типом, я решил использовать Benchmark :

#!/usr/bin/perl

use strict; use warnings;
use Benchmark qw( cmpthese );

cmpthese -5,  {
    goatse => sub { my $n = () = 'A' .. 'Z' },
    anon   => sub { my $n = @{[ 'A' .. 'Z' ]}},
};

Я запускал тест несколько раз, и назначение пустого списка имело небольшое преимущество во всех случаях. Если бы разница была чисто случайной, то вероятность наблюдения 10 таймингов в пользу козла составляет менее 0,1%, поэтому я предполагаю, что имеется какое-то короткое замыкание.

С другой стороны, тест производительности @daotoad, размещенный в комментариях, вероятно, дает более полную картину:

#!/usr/bin/perl

use strict; use warnings;
use Benchmark qw( cmpthese );

use constant START => 1;
use constant STOP => 1000;

my $start = START;
my $stop = STOP;

cmpthese -5, {
    anon => sub { my $n = @{[ $start .. $stop ]}},
    goatse => sub { my $n = () = $start .. $stop },
    canon => sub { my $n = @{[ START .. STOP ]}},
    cgoatse => sub { my $n = () = START .. STOP },
};

Типичные результаты на моем компьютере (Windows XP Pro SP3, Core 2 Duo, 2 ГБ памяти, ActiveState perl 5.10.1.1006):

           Rate    anon cgoatse  goatse   canon
anon     5207/s      --    -45%    -49%    -51%
cgoatse  9522/s     83%      --     -7%    -10%
goatse  10201/s     96%      7%      --     -4%
canon   10636/s    104%     12%      4%      --

А, с:

use constant START => 'AAAA';
use constant STOP => 'ZZZZ';

результаты:

          Rate    anon  goatse cgoatse   canon
anon    1.73/s      --    -12%    -16%    -17%
goatse  1.98/s     14%      --     -4%     -5%
cgoatse 2.06/s     19%      4%      --     -1%
canon   2.08/s     20%      5%      1%      --

Вывод:

Если сомневаетесь, используйте my $n = () = ...;

4 голосов
/ 09 февраля 2010

Нет. Это эквивалентно:

my $n = (() = ('a', 'b', 'c'));

... так как оператор присваивания является ассоциативным справа. Назначенный в скобках список справа сам по себе находится в скалярном контексте, поэтому его значением является число элементов в правой части.

1 голос
/ 02 марта 2010

Вы также можете использовать следующий код для подсчета количества элементов в массиве или списке

use strict;
use warnings;
my @array=(1,2,3,4);
my $i=0;
  foreach(@array)
  {
              $i++;
  }   
 print "The count is:$i\n";
1 голос
/ 09 февраля 2010

Как найти количество значений в список Perl?

Присвойте список переменной @array и получите размер @array, используя scalar(@array) или используя операцию $#array+1. Определите sub count {scalar @_} и используйте вызовы на count, если вам приходится много делать.

my $n = () = ('a', 'b', 'c'); # $n = 3

Конечно, вы можете использовать это ... если вы хотите, чтобы Perl продолжал иметь дурную славу в качестве языка только для чтения ...: (

1 голос
/ 09 февраля 2010

При использовании в скалярном контексте список оценивается числом элементов в нем:

my @list = ('a', 'b', 'c');
my $list_size = @list;

Чтобы выполнить явный тест, например, в условии if:

my @list = ('a', 'b', 'c');
if (scalar @list == 3) {
  print "@list"; # prints list separated with spaces
}

Это будет работать и без ключевого слова scalar. Однако это может затруднить сканирование вашего кода. Контекст - прекрасная идея, но она требует больше работы от читателя. Использование скаляра в явном виде позволяет читателю сразу увидеть, что вы оцениваете @list в скалярном контексте.

0 голосов
/ 09 февраля 2010

Чтобы узнать размер массива:

  1. Используйте scalar(), чтобы сделать его явным (для ссылок на массивы вам нужно отсылать их через @{...}):

    $ perl -e '$n = scalar(qw(1 2 3)); print $n . "\n"'
    3
    
  2. Используйте $# (добавьте плюс один, чтобы получить размер):

    $ perl -e '$n = [ 1, 2, 3]; print $#$n . "\n"'
    2
    $ perl -e 'print $#{[ 1, 2, 3]} . "\n"'
    2
    

Perl: есть как минимум два способа сделать это:)

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