Знайдіть розмір масиву в Perl


243

Здається, я натрапив на кілька різних способів знайти розмір масиву. У чому різниця між цими трьома методами?

my @arr = (2);
print scalar @arr; # First way to print array size

print $#arr; # Second way to print array size

my $arrSize = @arr;
print $arrSize; # Third way to print array size

13
інші способи: print 0+@arr, print "".@arr,print ~~@arr
моб

3
@mob, гудок, можна уникнути, "".@arrбо "@arr"щось зовсім інше.
ikegami

39
"Другий спосіб" НЕ спосіб друкувати розмір масиву ...
tadmc

у скалярному контексті; @arr повертає розмір таблиці. $ x = @ arr - скалярний контекст. $ # arr повертає останній індекс масиву. індексація, починаючи з 0, тоді є істинним рівнянням $ # arr + 1 == @arr. Якщо ви пишете якийсь елемент поза порядком, наприклад $ arr [100] = 'будь-який', то таблиця автоматично збільшується до максимального індексу 100, а (включаючи індекс 0) до 101 елемента.
Znik

Відповіді:


234

Перший і третій способи однакові: вони оцінюють масив у скалярному контексті. Я вважаю, що це стандартний спосіб отримати розмір масиву.

Другий спосіб фактично повертає останній індекс масиву, який не є (як правило) таким же, як розмір масиву.


29
Розмір (1,2,3) становить 3, а індекси (за замовчуванням) 0, 1 і 2. Отже, $ # arr буде 2 у цьому випадку, а не 3.
Nate CK

5
Заздалегідь визначена змінна $[вказує "Індекс першого елемента в масиві та першого символу в підрядку" ( perldoc perlvar). За замовчуванням він встановлений на 0, а встановити його на будь-що, крім 0, дуже не рекомендується.
Кіт Томпсон

5
@Keith Томпсон, $[не вражає (і це вже десятиліття). $[застаріло. Використання $[видає попередження про анулювання, навіть якщо попередження не включаються. Призначення нічого, крім нуля, $[буде помилкою в 5.16. Чи можемо ми перестати згадувати $[вже?
ikegami

2
@Keith Thompson, старший за 5.14. Але, як я вже говорив, його відштовхують і застарівають набагато довше, ніж хтось, хто використовує, $[буде знати про його наслідки.
ikegami

7
@ikegami: Так, але хтось намагається зрозуміти різницю між scalar @arrі все ж$#arr повинен розуміти можливі наслідки , хоча вони рідкісні. $[
Кіт Томпсон

41

По-перше, другий не рівноцінний двом іншим. $#arrayповертає останній індекс масиву, який на один менше розміру масиву.

Інші два практично однакові. Ви просто використовуєте два різні засоби для створення скалярного контексту. Це зводиться до питання читабельності.

Я особисто віддаю перевагу наступному:

say 0+@array;          # Represent @array as a number

Я вважаю це більш зрозумілим, ніж

say scalar(@array);    # Represent @array as a scalar

і

my $size = @array;
say $size;

Остання виглядає цілком чітко, як це, але я вважаю, що додаткова лінія забирає чіткість, коли є частиною іншого коду. Це корисно для викладання того, що @arrayробиться в скалярному контексті, і, можливо, якщо ви хочете використовувати $sizeкілька разів.


15
Особисто я віддаю перевагу версії, яка використовує ключове слово «скаляр», тому що це досить явно, що це змушує скалярний контекст. my $size=@arrayСхоже, це може бути помилкою, коли був використаний неправильний сигіл.
Nate CK

5
Це дійсно погана ідея. Люди, які користуються scalarбез причини, засвоюють неправильний урок. Вони починають головувати, що оператори повертають списки, які можна примусити до скалярів. Бачили це десятки разів.
ikegami

2
Чому це "без причини"? Ви використовуєте, scalarтому що ви примушуєте список до скалярного контексту. Це правильна причина його використання. Ваш приклад робить саме те саме, але покладається на те, що робить Perl, коли ви оцінюєте змінну списку в неявно скалярному контексті. Таким чином, ваш приклад вимагає від читача знати про неявну поведінку Перла в цьому контексті. Ви просто додаєте до виразу ще один шар неявної поведінки, і Perl вже має занадто багато неявної поведінки, що вам доведеться міркувати, щоб розшифрувати програму.
Nate CK

2
@Nate CK, Re "Чому це" немає причини "? Ви використовуєте, scalarтому що ви прив'язуєте список до скалярного контексту", Ви доводили мою думку про те, що ви засвоїли неправильний урок. Це абсолютно помилково. Жоден список не примусовий до цього scalar. (Якби це було, scalar(@array)і scalar(@array[0..$#array])поверне те саме.) scalar(@array)Каже @arrayповернути скаляра, з яким ви вже сказали my $size=.
ikegami

2
Вірите чи ні, розробникам доводиться налагоджувати код, написаний іншими розробниками. І розробникам доводиться налагоджувати код, який вони написали три роки тому.
Nate CK

27

Він отримує розмір, примушуючи масив до скалярного контексту, в якому він оцінюється як його розмір:

print scalar @arr;

Це ще один спосіб примусити масив до скалярного контексту, оскільки він присвоюється скалярній змінній:

my $arrSize = @arr;

Це отримує індекс останнього елемента в масиві, тому він насправді розмір мінус 1 (якщо індекси починаються з 0, що регулюється в Perl, хоча це зазвичай є поганою ідеєю):

print $#arr;

Цей останній не дуже добре використовувати для отримання розміру масиву. Було б корисно, якщо ви просто хочете отримати останній елемент масиву:

my $lastElement = $arr[$#arr];

Крім того, як ви бачите тут, на Stack Overflow, більшість підсвічувачів синтаксису ця конструкція не обробляється правильно ...


2
Сторінка: просто використовуйте $arr[-1]для отримання останнього елемента. І $arr[-2]щоб отримати передостаннє тощо.
tuomassalo

1
@tuomassalo: Я згоден, що ваша пропозиція є кращим підходом. Зрештою, $#arrце не дуже корисна функція, і не випадково інші мови не мають її.
Нейт СК

6

Щоб використовувати другий спосіб, додайте 1:

print $#arr + 1; # Second way to print array size

for [0..$#array] { print $array[$_ ] } працює дуже добре, хоча якщо метою отримання кількості елементів є перегляд масиву. Перевагою є те, що ви отримуєте елемент, а також лічильник, який вирівнюється.
Westrock

5

Усі троє дають однаковий результат, якщо трохи змінити другий:

my @arr = (2, 4, 8, 10);

print "First result:\n";
print scalar @arr; 

print "\n\nSecond result:\n";
print $#arr + 1; # Shift numeration with +1 as it shows last index that starts with 0.

print "\n\nThird result:\n";
my $arrSize = @arr;
print $arrSize;

5
Чи це щось відрізняється від того, що вже було сказано у цій відповіді та у цій ?
devnull

5

Приклад:

my @a = (undef, undef);
my $size = @a;

warn "Size: " . $#a;   # Size: 1. It's not the size
warn "Size: " . $size; # Size: 2

2

Розділ «Типи змінних Perl» документації на perlintro містить

Спеціальна змінна $#arrayповідомляє вам індекс останнього елемента масиву:

print $mixed[$#mixed];       # last element, prints 1.23

Ви можете спокуситись $#array + 1сказати, скільки предметів у масиві. Не турбуйся. Як це буває, використання @arrayтуди, де Perl розраховує знайти скалярне значення ("у скалярному контексті"), дасть вам кількість елементів у масиві:

if (@animals < 5) { ... }

Документація perldata також висвітлює це у розділі «Скалярні значення» .

Якщо ви оцінюєте масив у скалярному контексті, він повертає довжину масиву. (Зверніть увагу, що це не стосується списків, які повертають останнє значення, як-от оператор C-коми, а також вбудованих функцій, які повертають все, що вони відчувають, що повертаються.) Наступне завжди вірно:

scalar(@whatever) == $#whatever + 1;

Деякі програмісти вирішують використовувати явну конверсію, щоб не залишати нічого сумніву:

$element_count = scalar(@whatever);

Раніше в цьому ж розділі документи, як отримати індекс останнього елемента масиву.

Довжина масиву - скалярне значення. Ви можете знайти довжину масиву @days, оцінивши $#days, як у csh. Однак це не довжина масиву; це підпис останнього елемента, який має інше значення, оскільки зазвичай є 0-й елемент.


2

Існують різні способи друку розміру масиву. Ось значення усіх: Скажімо, наш масив єmy @arr = (3,4);

Спосіб 1: скалярний

Це правильний спосіб отримати розмір масивів.

print scalar @arr;  # prints size, here 2

Спосіб 2: Номер індексу

$#arrдає останній індекс масиву. тож якщо масив розміром 10, то його останнім індексом буде 9.

print $#arr;     # prints 1, as last index is 1
print $#arr + 1; # Add 1 to last index to get array size

Ми додаємо тут 1, вважаючи масив як 0-індексованим . Але, якщо на її основі не нульове значення, то ця логіка вийде з ладу .

perl -le 'local $[ = 4; my @arr=(3,4); print $#arr + 1;'   # prints 6

Наведений вище приклад 6 друкує, тому що ми встановили його початковий індекс на 4. Тепер індекс буде 5 та 6, з елементами 3 та 4 відповідно.

Спосіб 3:

Коли масив використовується в скалярному контексті, він повертає розмір масиву

my $size = @arr;
print $size;   # prints size, here 2

Насправді метод 3 та метод 1 однакові.


2

Із perldoc perldata , що має бути безпечним для цитування:

Це завжди вірно:

scalar(@whatever) == $#whatever + 1;

Тільки до тих пір, поки ви не зробите + # ++ і загадково не збільшите розмір або масив.

Індекси масиву починаються з 0.

і

Ви можете обрізати масив аж до нічого, призначивши йому null list (). Наступні:

    @whatever = ();
    $#whatever = -1;

Що підводить мене до того, що я шукав, а саме - як визначити масив порожнім. Я знайшов це, якщо $ # empty == -1;



0

Щоб знайти розмір масиву, використовуйте scalarключове слово:

print scalar @array;

Для з'ясування останнього індексу масиву існує $#(змінна Perl за замовчуванням). Він дає останній індекс масиву. Оскільки масив починається з 0, ми отримуємо розмір масиву, додаючи його до $#:

print "$#array+1";

Приклад:

my @a = qw(1 3 5);
print scalar @a, "\n";
print $#a+1, "\n";

Вихід:

3

3
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.