Znajdź rozmiar tablicy w Perlu

243

Wydaje mi się, że natknąłem się na kilka różnych sposobów, aby znaleźć rozmiar tablicy. Jaka jest różnica między tymi trzema metodami?

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
David
źródło
13
inne sposoby: print 0+@arr, print "".@arr,print ~~@arr
mob
3
@mob, szum, można chcieć uniknąć, "".@arrponieważ "@arr"robi to coś zupełnie innego.
ikegami,
39
„Drugi sposób” NIE jest sposobem na wydrukowanie rozmiaru tablicy ...
tadmc,
w kontekście skalarnym; @arr zwraca rozmiar tabeli. $ x = @ arr to kontekst skalarny. $ # arr zwraca ostatni indeks tablicy. indeksowanie zaczyna się od 0, wtedy jest to prawdziwe równanie $ # arr + 1 == @arr. Jeśli napiszesz jakiś element poza kolejnością, na przykład $ arr [100] = 'any', wówczas tabela zostanie automatycznie zwiększona do maksymalnego indeksu 100, a (łącznie z indeksem 0) do 101 elementów.
Znik

Odpowiedzi:

234

Pierwszy i trzeci sposób są takie same: oceniają tablicę w kontekście skalarnym. Uznałbym to za standardowy sposób na uzyskanie rozmiaru tablicy.

Drugi sposób faktycznie zwraca ostatni indeks tablicy, który nie jest (zwykle) taki sam jak rozmiar tablicy.

Chris Jester-Young
źródło
29
Rozmiar (1,2,3) wynosi 3, a indeksy to (domyślnie) 0, 1 i 2. Zatem $ arr będzie w tym przypadku 2, a nie 3.
Nate CK
5
Wstępnie zdefiniowana zmienna $[określa „Indeks pierwszego elementu w tablicy i pierwszego znaku w podciągu” ( perldoc perlvar). Domyślnie jest ustawiony na 0, a ustawienie go na wartość inną niż 0 jest wysoce odradzane.
Keith Thompson,
5
@Keith Thompson, $[jest odradzany (i był przez dekadę). $[jest przestarzałe. Używanie $[wydaje ostrzeżenie o wycofaniu, nawet jeśli nie włącza się ostrzeżeń. Przypisanie niczego innego niż zero $[będzie błędem w 5.16. Czy możemy $[już przestać o tym wspominać ?
ikegami,
2
@ Keith Thompson, w rzeczywistości starszy niż 5.14. Ale tak jak powiedziałem, było to zniechęcone i przestarzałe o wiele dłużej, a ktoś używający $[wiedziałby o jego skutkach.
ikegami,
7
@ikegami: Tak, ale ktoś, kto próbuje zrozumieć różnicę scalar @arri nadal$#arr powinien zrozumieć możliwe skutki , choć są rzadkie. $[
Keith Thompson,
41

Po pierwsze, drugi nie jest równoważny dwóm pozostałym. $#arrayzwraca ostatni indeks tablicy, który jest o jeden mniejszy niż rozmiar tablicy.

Pozostałe dwa są praktycznie takie same. Po prostu używasz dwóch różnych środków do stworzenia kontekstu skalarnego. Wszystko sprowadza się do kwestii czytelności.

Osobiście wolę następujące:

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

Uważam, że to jaśniejsze niż

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

i

my $size = @array;
say $size;

Ten ostatni wygląda całkiem wyraźnie sam, ale uważam, że dodatkowa linia odbiera jasność, gdy jest częścią innego kodu. Jest to przydatne do nauczania tego, co @arrayrobi w kontekście skalarnym, a może jeśli chcesz użyć $sizewięcej niż raz.

ikegami
źródło
15
Osobiście wolę wersję, która używa słowa kluczowego „skalar”, ponieważ jest dość wyraźne, że wymusza kontekst skalarny. my $size=@arraywygląda na to, że błędem może być użycie niewłaściwej pieczęci.
Nate CK,
5
To naprawdę zły pomysł. Ludzie, którzy używają scalarbez powodu, uczą się złej lekcji. Zaczynają myśleć, że operatorzy zwracają listy, które można przekształcić w skalary. Widziałem to dziesiątki razy.
ikegami,
2
Dlaczego to „bez powodu”? Używasz, scalarponieważ wymuszasz listę w kontekście skalarnym. To jest właściwy powód, aby z niego korzystać. Twój przykład robi dokładnie to samo, ale opiera się na tym, co robi Perl, gdy oceniasz zmienną listy w niejawnie skalarnym kontekście. Zatem twój przykład wymaga od czytelnika wiedzy o domyślnym zachowaniu Perla w tym kontekście. Po prostu dodajesz do wyrażenia jeszcze jedną warstwę niejawnego zachowania, a Perl ma już zbyt wiele niejawnych zachowań, które musisz uzasadnić, aby rozszyfrować program.
Nate CK
2
@Nate CK, Re „Dlaczego to„ bez powodu ”? Używasz, scalarponieważ zmuszasz listę do kontekstu skalarnego”, Udowadniasz mój punkt widzenia na temat wyciągania niewłaściwej lekcji. To jest całkowicie fałszywe. Żadna lista nigdy nie jest wymuszana przez scalar. (Jeśli tak, scalar(@array)i scalar(@array[0..$#array])zwróci to samo.) scalar(@array)Mówi @arrayo zwróceniu skalara, z którym już powiedziałeś, aby to zrobić my $size=.
ikegami
2
Wierzcie lub nie, programiści muszą debugować kod napisany przez innych programistów. Programiści muszą debugować kod, który napisali trzy lata temu.
Nate CK
27

Rozmiar uzyskuje się, zmuszając tablicę do kontekstu skalarnego, w którym jest ona oceniana jako jej rozmiar:

print scalar @arr;

Jest to kolejny sposób na zmuszenie tablicy do kontekstu skalarnego, ponieważ jest ona przypisana do zmiennej skalarnej:

my $arrSize = @arr;

Pobiera indeks ostatniego elementu w tablicy, więc w rzeczywistości jest to rozmiar minus 1 (zakładając, że indeksy zaczynają się od 0, które można regulować w Perlu, chociaż jest to zwykle zły pomysł):

print $#arr;

Ten ostatni nie jest zbyt dobry do uzyskania rozmiaru tablicy. Przydałoby się, jeśli chcesz tylko uzyskać ostatni element tablicy:

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

Ponadto, jak widać tutaj na przepełnieniu stosu, ta konstrukcja nie jest obsługiwana poprawnie przez większość wyróżników składni ...

Nate CK
źródło
2
Krótka informacja: wystarczy użyć, $arr[-1]aby uzyskać ostatni element. I $arr[-2]dostać przedostatni, i tak dalej.
tuomassalo
1
@tuomassalo: Zgadzam się, że twoja sugestia jest lepszym podejściem. Z perspektywy czasu $#arrnie jest to bardzo przydatna funkcja i nieprzypadkowo inne języki jej nie mają.
Nate CK,
6

Aby użyć drugiego sposobu, dodaj 1:

print $#arr + 1; # Second way to print array size
jhoanna
źródło
for [0..$#array] { print $array[$_ ] } działa naprawdę dobrze, jeśli celem uzyskania liczby elementów jest iteracja po tablicy. Zaletą jest to, że dostajesz element, a także licznik, które są wyrównane.
Westrock
5

Wszystkie trzy dają ten sam wynik, jeśli nieco zmodyfikujemy drugi:

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;
Strefa
źródło
5
Czy to coś innego niż to, o czym już wspomniano w tej odpowiedzi i tej ?
devnull
5

Przykład:

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

warn "Size: " . $#a;   # Size: 1. It's not the size
warn "Size: " . $size; # Size: 2
dimas
źródło
2

Sekcja „Perl typy zmiennych” z dokumentacji perlintro zawiera

Zmienna specjalna $#arrayinformuje o indeksie ostatniego elementu tablicy:

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

Możesz ulec pokusie, aby $#array + 1powiedzieć ci, ile przedmiotów jest w tablicy. Nie zawracaj sobie głowy Tak się składa, że ​​użycie miejsca, w @arrayktórym Perl oczekuje znalezienia wartości skalarnej („w kontekście skalarnym”), da ci liczbę elementów w tablicy:

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

Dokumentacja perldata obejmuje to również w sekcji „Wartości skalarne” .

Jeśli oceniasz tablicę w kontekście skalarnym, zwraca ona długość tablicy. (Zauważ, że nie jest to prawdą w przypadku list, które zwracają ostatnią wartość, jak operator przecinka C, ani wbudowanych funkcji, które zwracają cokolwiek, jak im się wydaje, powrót). Zawsze jest tak:

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

Niektórzy programiści decydują się na użycie jawnej konwersji, aby nie pozostawiać wątpliwości:

$element_count = scalar(@whatever);

Wcześniej w tej samej sekcji opisano, jak uzyskać indeks ostatniego elementu tablicy.

Długość tablicy jest wartością skalarną. Możesz znaleźć długość tablicy @days, oceniając $#days, jak w csh. Nie jest to jednak długość tablicy; jest to indeks dolny ostatniego elementu, który ma inną wartość, ponieważ zwykle jest to 0 element.

Greg Bacon
źródło
2

Istnieją różne sposoby drukowania rozmiaru tablicy. Oto znaczenie wszystkich: Powiedzmy, że nasza tablica jestmy @arr = (3,4);

Metoda 1: skalar

To właściwy sposób na uzyskanie rozmiaru tablic.

print scalar @arr;  # prints size, here 2

Metoda 2: Numer indeksu

$#arrdaje ostatni indeks tablicy. więc jeśli tablica ma rozmiar 10, to jej ostatni indeks wynosiłby 9.

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

Dodajemy tutaj 1, biorąc pod uwagę tablicę jako 0-indeksowaną . Ale jeśli nie jest to zero, logika się nie powiedzie .

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

Powyższy przykład drukuje 6, ponieważ ustawiliśmy jego początkowy indeks na 4. Teraz indeks będzie wynosił 5 i 6, odpowiednio z elementami 3 i 4.

Metoda 3:

Gdy tablica jest używana w kontekście skalarnym, zwraca rozmiar tablicy

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

W rzeczywistości metoda 3 i metoda 1 są takie same.

Kamal Nayan
źródło
2

Z perldoc perldata , które powinno być bezpiecznie cytować:

Zawsze spełnione są następujące warunki:

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

Tak długo, jak nie będziesz # $ ++ i w tajemniczy sposób zwiększysz rozmiar lub swoją tablicę.

Indeksy tablicowe zaczynają się od 0.

i

Możesz skrócić tablicę do zera, przypisując jej pustą listę (). Następujące są równoważne:

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

To prowadzi mnie do tego, czego szukałem, czyli do wykrycia, że ​​tablica jest pusta. Znalazłem, jeśli $ # pusty == -1;

jwal
źródło
1

A int(@array)może zagraża argumentowi skalarnemu.

Odblaskowy
źródło
0

Aby znaleźć rozmiar tablicy, użyj scalarsłowa kluczowego:

print scalar @array;

Aby znaleźć ostatni indeks tablicy, istnieje $#(zmienna domyślna Perl). Daje ostatni indeks tablicy. Gdy tablica zaczyna się od 0, otrzymujemy rozmiar tablicy, dodając jedną do $#:

print "$#array+1";

Przykład:

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

Wynik:

3

3
Sandeep_black
źródło