Trouver la taille d'un tableau en Perl

243

Il me semble avoir rencontré plusieurs façons différentes de trouver la taille d'un tableau. Quelle est la différence entre ces trois méthodes?

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
la source
13
d' autres moyens: print 0+@arr, print "".@arr,print ~~@arr
mob
3
@mob, hum, on peut vouloir éviter tout "".@arrcomme "@arr"quelque chose de très différent.
ikegami
39
La "deuxième façon" n'est PAS un moyen d'imprimer la taille du tableau ...
tadmc
dans un contexte scalaire; @arr renvoie la taille de la table. $ x = @ arr est un contexte scalaire. $ # arr renvoie le dernier index du tableau. indexation commençant à 0, alors est la vraie équation $ # arr + 1 == @arr. Si vous écrivez un élément dans le désordre, par exemple $ arr [100] = 'any', la table est automatiquement augmentée à l'index max 100 et (y compris l'index 0) à 101 éléments.
Znik

Réponses:

234

Les première et troisième façons sont les mêmes: elles évaluent un tableau dans un contexte scalaire. Je considère que c'est la façon standard d'obtenir la taille d'un tableau.

La deuxième façon renvoie en fait le dernier index du tableau, qui n'est pas (généralement) le même que la taille du tableau.

Chris Jester-Young
la source
29
La taille de (1,2,3) est 3, et les index sont (par défaut) 0, 1 et 2. Donc, $ # arr sera 2 dans ce cas, pas 3.
Nate CK
5
La variable prédéfinie $[spécifie "L'index du premier élément d'un tableau et du premier caractère d'une sous-chaîne" ( perldoc perlvar). Il est défini sur 0 par défaut, et le définir sur autre chose que 0 est fortement déconseillé.
Keith Thompson
5
@Keith Thompson, $[est découragé (et ce depuis une décennie). $[est obsolète. L'utilisation $[émet un avertissement de dépréciation même lorsque l'on n'active pas les avertissements. Assigner autre chose que zéro à $[sera une erreur en 5.16. Pouvons-nous arrêter de mentionner $[déjà?
ikegami
2
@Keith Thompson, plus âgé que 5,14, en fait. Mais comme je l'ai dit, cela a été découragé et déconseillé depuis bien plus longtemps que cela, et quelqu'un $[qui en connaîtrait les effets.
ikegami
7
@ikegami: Oui, mais quelqu'un qui essaie de comprendre la différence entre scalar @arret $#arrdevrait toujours comprendre les effets possibles de $[, aussi rares soient-ils.
Keith Thompson
41

Premièrement, le second n'est pas équivalent aux deux autres. $#arrayrenvoie le dernier index du tableau, qui est un de moins que la taille du tableau.

Les deux autres sont pratiquement les mêmes. Vous utilisez simplement deux moyens différents pour créer un contexte scalaire. Cela revient à une question de lisibilité.

Personnellement, je préfère ce qui suit:

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

Je trouve cela plus clair que

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

et

my $size = @array;
say $size;

Ce dernier semble assez clair seul comme celui-ci, mais je trouve que la ligne supplémentaire enlève de la clarté lorsqu'elle fait partie d'un autre code. Il est utile pour enseigner ce qui @arrayfait dans un contexte scalaire, et peut-être si vous souhaitez utiliser $sizeplus d'une fois.

ikegami
la source
15
Personnellement, je préfère la version qui utilise le mot-clé "scalaire", car il est assez explicite de forcer un contexte scalaire. my $size=@arrayil semble que ce soit une erreur lorsque le mauvais sceau a été utilisé.
Nate CK
5
C'est vraiment une mauvaise idée. Les gens qui utilisent scalarsans raison apprennent la mauvaise leçon. Ils commencent à penser que les opérateurs renvoient des listes qui peuvent être forcées en scalaires. Vu des dizaines de fois.
ikegami
2
Pourquoi est-ce "sans raison"? Vous utilisez scalarparce que vous contraignez la liste à un contexte scalaire. C'est la bonne raison de l'utiliser. Votre exemple fait exactement la même chose, mais repose sur ce que Perl fait lorsque vous évaluez une variable de liste dans un contexte implicitement scalaire. Ainsi, votre exemple nécessite que le lecteur connaisse le comportement implicite de Perl dans ce contexte. Vous ajoutez simplement une couche supplémentaire de comportement implicite à l'expression, et Perl a déjà trop de comportement implicite que vous devez raisonner pour déchiffrer un programme.
Nate CK
2
@Nate CK, Re "Pourquoi est-ce" pas de raison "? Vous utilisez scalarparce que vous contraignez la liste à un contexte scalaire", Vous avez prouvé mon point sur la mauvaise leçon. C'est complètement faux. Aucune liste n'est jamais contrainte par scalar. (Si c'était le cas, scalar(@array)et scalar(@array[0..$#array])retournerait la même chose.) scalar(@array)Dit @arrayde retourner un scalaire, avec lequel vous lui avez déjà dit de faire my $size=.
ikegami
2
Croyez-le ou non, les développeurs doivent déboguer du code écrit par d'autres développeurs. Et les développeurs doivent déboguer le code qu'ils ont écrit il y a trois ans.
Nate CK
27

Cela obtient la taille en forçant le tableau dans un contexte scalaire, dans lequel il est évalué comme sa taille:

print scalar @arr;

C'est une autre façon de forcer le tableau dans un contexte scalaire, car il est affecté à une variable scalaire:

my $arrSize = @arr;

Cela obtient l'index du dernier élément du tableau, il s'agit donc en fait de la taille moins 1 (en supposant que les index commencent à 0, ce qui est réglable en Perl, bien que cela soit généralement une mauvaise idée):

print $#arr;

Ce dernier n'est pas vraiment bon à utiliser pour obtenir la taille du tableau. Il serait utile si vous souhaitez simplement obtenir le dernier élément du tableau:

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

De plus, comme vous pouvez le voir ici sur Stack Overflow, cette construction n'est pas gérée correctement par la plupart des surligneurs de syntaxe ...

Nate CK
la source
2
Un sidenote: utilisez simplement $arr[-1]pour obtenir le dernier élément. Et $arr[-2]pour obtenir l'avant-dernier, et ainsi de suite.
tuomassalo
1
@tuomassalo: Je suis d'accord que votre suggestion est une meilleure approche. Rétrospectivement, ce $#arrn'est pas une fonctionnalité très utile, et ce n'est pas un hasard si d'autres langues ne l'ont pas.
Nate CK
6

Pour utiliser la deuxième méthode, ajoutez 1:

print $#arr + 1; # Second way to print array size
jhoanna
la source
for [0..$#array] { print $array[$_ ] } fonctionne très bien si le but d'obtenir le nombre d'éléments est de parcourir le tableau. L'avantage étant que vous obtenez l'élément ainsi qu'un compteur alignés.
Westrock
5

Tous les trois donnent le même résultat si nous modifions un peu le second:

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;
Zon
la source
5
Est-ce quelque chose de différent de ce qui a déjà été mentionné dans cette réponse et celle- ci?
devnull
5

Exemple:

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

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

La section «Types de variables Perl» de la documentation perlintro contient

La variable spéciale $#arrayvous indique l'index du dernier élément d'un tableau:

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

Vous pourriez être tenté d'utiliser $#array + 1pour vous dire combien d'éléments il y a dans un tableau. Ne t'embête pas. En l'occurrence, l'utilisation de l' @arrayendroit où Perl s'attend à trouver une valeur scalaire («dans un contexte scalaire») vous donnera le nombre d'éléments dans le tableau:

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

La documentation des perldata couvre également cela dans la section «Valeurs scalaires» .

Si vous évaluez un tableau dans un contexte scalaire, il renvoie la longueur du tableau. (Notez que ce n'est pas le cas des listes, qui renvoient la dernière valeur, comme l'opérateur virgule C, ni des fonctions intégrées, qui renvoient tout ce qu'elles ont envie de retourner.) Ce qui suit est toujours vrai:

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

Certains programmeurs choisissent d'utiliser une conversion explicite afin de ne laisser aucun doute:

$element_count = scalar(@whatever);

Plus haut dans la même section explique comment obtenir l'index du dernier élément d'un tableau.

La longueur d'un tableau est une valeur scalaire. Vous pouvez trouver la longueur du tableau @daysen évaluant $#days, comme dans csh. Cependant, ce n'est pas la longueur du tableau; c'est l'indice du dernier élément, qui est une valeur différente car il y a normalement un 0ème élément.

Greg Bacon
la source
2

Il existe différentes façons d'imprimer la taille du tableau. Voici la signification de tous: Disons que notre tableau estmy @arr = (3,4);

Méthode 1: scalaire

C'est la bonne façon d'obtenir la taille des tableaux.

print scalar @arr;  # prints size, here 2

Méthode 2: numéro d'index

$#arrdonne le dernier index d'un tableau. donc si le tableau est de taille 10 alors son dernier index serait 9.

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

Nous ajoutons 1 ici en considérant le tableau comme indexé 0 . Mais, s'il n'est pas basé sur zéro, cette logique échouera .

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

L'exemple ci-dessus imprime 6, car nous avons défini son index initial à 4. L'index serait maintenant 5 et 6, avec les éléments 3 et 4 respectivement.

Méthode 3:

Lorsqu'un tableau est utilisé dans un contexte scalaire, il renvoie la taille du tableau

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

En fait, la méthode 3 et la méthode 1 sont identiques.

Kamal Nayan
la source
2

De perldoc perldata , qui devrait être sûr de citer:

Ce qui suit est toujours vrai:

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

Tant que vous ne faites pas $ # n'importe quoi ++ et augmentez mystérieusement la taille ou votre tableau.

Les indices de tableau commencent par 0.

et

Vous pouvez tronquer un tableau à rien en lui affectant la liste nulle (). Les éléments suivants sont équivalents:

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

Ce qui m'amène à ce que je cherchais, à savoir comment détecter que le tableau est vide. Je l'ai trouvé si $ # empty == -1;

jwal
la source
1

Qu'en est-il de int(@array) est-il car il menace l'argument comme scalaire.

Réfléchissant
la source
0

Pour trouver la taille d'une utilisation du tableau le scalarmot - clé:

print scalar @array;

Pour connaître le dernier index d'un tableau, il existe $#(variable Perl par défaut). Il donne le dernier index d'un tableau. Lorsqu'un tableau commence à 0, nous obtenons la taille du tableau en en ajoutant un à $#:

print "$#array+1";

Exemple:

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

Production:

3

3
Sandeep_black
la source