Подсчет элементов массива в Perl

Как получить общее количество элементов в массиве, а НЕ последний идентификатор?

Ни один из двух способов, которые я нашел для этого, не работает:

my @a;
# Add some elements (no consecutive ids)
$a[0]= '1';
$a[5]= '2';
$a[23]= '3';

print $#a, "\n"; # Prints 23
print scalar(@a), "\n"; # Prints 24

Я ожидал получить 3...


person grilix    schedule 14.05.2009    source источник


Ответы (6)


Правка: хэш против массива

Как правильно указал cincodenada в комментарии, ysth дал лучший ответ: я должен был ответить на ваш вопрос другим вопросом: «Вы действительно хотите использовать массив Perl? Хэш может быть более подходящим».

Массив выделяет память для всех возможных индексов, вплоть до самого большого из использованных до сих пор. В вашем примере вы выделяете 24 ячейки (но используете только 3). Напротив, хеш выделяет место только для тех полей, которые фактически используются.

Решение для массива: скалярный grep

Вот два возможных решения (объяснение см. ниже):

print scalar(grep {defined $_} @a), "\n";  # prints 3
print scalar(grep $_, @a), "\n";            # prints 3

Объяснение: после добавления $a[23] ваш массив действительно содержит 24 элемента --- но большинство из них не определены (что также оценивается как ложное). Вы можете подсчитать количество определенных элементов (как это сделано в первом решении) или количество истинных элементов (второе решение).

В чем разница? Если вы установите $a[10]=0, то первое решение засчитает его, а второе — нет (поскольку 0 ложно, но определено). Если вы установите $a[3]=undef, ни одно из решений не засчитает его.

Хэш-решение (по yst)

Как предлагает другое решение, вы можете работать с хешем и избежать всех проблем:

$a{0}  = 1;
$a{5}  = 2;
$a{23} = 3;
print scalar(keys %a), "\n";  # prints 3

Это решение подсчитывает нули и значения undef.

person Yaakov Belch    schedule 14.05.2009
comment
Последняя часть этого ответа является правильной. grillix, кажется, из фона PHP. То, что PHP называет массивами, на самом деле больше похоже на хэши Perl, и в подобных случаях следует использовать последние. - person cincodenada; 06.12.2012
comment
Как эту идею можно распространить на многомерные массивы в Perl? - person damned; 13.09.2013
comment
Небольшое исправление в формате grep: print scalar(grep { $_ } @a), "\n"; - person arikin; 30.03.2015
comment
@arikin: я добавил запятую, чтобы исправить синтаксическую проблему. Спасибо, что указали на это! - person Yaakov Belch; 30.03.2015

Похоже, вам нужен разреженный массив. В обычном массиве будет 24 элемента, а в разреженном — 3. В Perl мы эмулируем разреженные массивы с помощью хэшей:

#!/usr/bin/perl

use strict;
use warnings;

my %sparse;

@sparse{0, 5, 23} = (1 .. 3);

print "there are ", scalar keys %sparse, " items in the sparse array\n",
    map { "\t$sparse{$_}\n" } sort { $a <=> $b } keys %sparse;

Функция keys в скалярном контексте вернет количество элементов в разреженном массиве. Единственным недостатком использования хэша для эмуляции разреженного массива является то, что вы должны сортировать ключи перед повторением по ним, если их порядок важен.

Вы также должны помнить об использовании функции delete для удаления элементов из разреженного массива (просто недостаточно установить для них значение undef).

person Chas. Owens    schedule 14.05.2009
comment
Это точно. Однако Tie::IxHash является необязательным; в вашем примере это кажется ненужным. Кроме того, нет необходимости указывать предикат для сортировки, так как он используется по умолчанию. Ключи сортировки %sparse также работают. - person spoulson; 14.05.2009
comment
Упс, Tie::IxHash остался из другого примера. Позвольте мне удалить это. - person Chas. Owens; 14.05.2009
comment
@Spoulson Нет, сортировка по умолчанию является лексической, а не числовой, поэтому ключи (1, 2 и 10) будут отсортированы (1, 10, 2). - person Chas. Owens; 14.05.2009

Возможно, вам нужен хеш вместо (или в дополнение). Массивы — это упорядоченный набор элементов; если вы создаете $foo[23], вы неявно создаете $foo[0] через $foo[22].

person ysth    schedule 14.05.2009

вывести скалярную группу grep { определено $_ } @a;

person kcwu    schedule 14.05.2009
comment
Объяснение: Perl на самом деле не имеет разреженных массивов, как того хочет grilix. Если вы скажете мой @a; $а[10]=5; затем perl создает массив с 11 элементами: первые 10 заполнены «undef», 11-й заполнен «5». То, что скаляр @a и $#a сообщает, всегда является общей длиной/последним индексом. kcwu фильтрует массив для подсчета только определенных записей. - person user55400; 14.05.2009
comment
Это работает, но это не хорошо. Функция grep — это O(n), что означает, что если у вас есть @a[1, 1_000_000] = (1, 2); затем он должен просмотреть каждый из 1 000 000 элементов, чтобы получить подсчет, это также означает, что вы будете занимать кучу памяти без причины, вместо этого используйте хэш. - person Chas. Owens; 14.05.2009
comment
Я.. Это работает, ЕСЛИ Я ДОЛЖЕН использовать массивы, но я думаю, что вместо этого я могу использовать хэши. В любом случае, он просто ответил на то, о чем я просил. Спасибо вам всем. - person grilix; 14.05.2009
comment
Можете ли вы добавить объяснение к своему ответу? Но без Edit:, Update: и т.п. ответ должен выглядеть так, как будто он был написан сегодня. - person Peter Mortensen; 27.04.2021

@people = qw( bob john linda ); 
$n = @people; # The number 3
Print " The number in the list is $n \n"; 

Выражения в Perl всегда возвращают значение, соответствующее их контексту.

Например, как насчет «имени» * массива? В контексте списка он дает список элементов. Но в скалярном контексте он возвращает количество элементов в массиве.

person Zhugo    schedule 28.12.2013

person    schedule
comment
Этот код имеет серьезные проблемы. Прежде всего, он нарушается, если элементы массива содержат пробелы. Во-вторых, он перебирает полный набор элементов массива один раз и набор определенных элементов дважды. В-третьих, как и все решения на основе массива, он не имеет возможности отличить undef, заданные пользователем, от пустых слотов в массиве (это может быть неплохо, в зависимости от того, как используется код). - person Chas. Owens; 29.09.2012