Tìm kích thước của một mảng trong Perl


243

Tôi dường như đã bắt gặp một số cách khác nhau để tìm kích thước của một mảng. Sự khác biệt giữa ba phương pháp này là gì?

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
cách khác: print 0+@arr, print "".@arr,print ~~@arr
đám đông

3
@mob, hum, người ta có thể muốn tránh "".@arrlàm "@arr"điều gì đó khá khác biệt.
ikegami

39
"Cách thứ hai" KHÔNG phải là cách in kích thước mảng ...
tadmc

trong ngữ cảnh vô hướng; @arr trả về kích thước bảng. $ x = @ mảng là bối cảnh vô hướng. $ # Array trả về chỉ mục cuối cùng của mảng. lập chỉ mục bắt đầu từ 0, sau đó là phương trình đúng $ # Array + 1 == @arr. Nếu bạn viết một số phần tử không theo thứ tự, ví dụ $ Array [100] = 'any', thì bảng sẽ tự động được tăng lên chỉ số tối đa 100 và (bao gồm chỉ số 0) thành 101 phần tử.
Znik

Câu trả lời:


234

Cách thứ nhất và thứ ba giống nhau: họ đánh giá một mảng trong bối cảnh vô hướng. Tôi sẽ coi đây là cách tiêu chuẩn để có được kích thước của một mảng.

Cách thứ hai thực sự trả về chỉ mục cuối cùng của mảng, không (thường) giống với kích thước mảng.


29
Kích thước của (1,2,3) là 3 và các chỉ mục là (theo mặc định) 0, 1 và 2. Vì vậy, $ # Array sẽ là 2 trong trường hợp này, không phải 3.
Nate CK

5
Biến được xác định trước $[chỉ định "Chỉ mục của phần tử đầu tiên trong một mảng và của ký tự đầu tiên trong chuỗi con" ( perldoc perlvar). Nó được đặt thành 0 theo mặc định và đặt nó thành bất kỳ thứ gì khác 0 là không được khuyến khích.
Keith Thompson

5
@Keith Thompson, $[không được khuyến khích (và đã được một thập kỷ). $[bị phản đối Sử dụng $[các vấn đề cảnh báo khấu hao ngay cả khi người ta không bật cảnh báo. Chỉ định bất cứ điều gì nhưng không có $[sẽ là một lỗi trong 5.16. Chúng ta có thể ngừng đề cập đến $[đã?
ikegami

2
@Keith Thompson, Cũ hơn 5.14, thực sự. Nhưng như tôi đã nói, nó không được khuyến khích và phản đối lâu hơn thế, và ai đó sử dụng $[sẽ biết về tác dụng của nó.
ikegami

7
@ikegami: Có, nhưng ai đó đang cố gắng hiểu sự khác biệt giữa scalar @arrvẫn$#arr nên hiểu những ảnh hưởng có thể có , hiếm khi xảy ra. $[
Keith Thompson

41

Thứ nhất, thứ hai không tương đương với hai cái còn lại. $#arraytrả về chỉ mục cuối cùng của mảng, nhỏ hơn một kích thước của mảng.

Hai cái khác hầu như giống nhau. Bạn chỉ đơn giản là sử dụng hai phương tiện khác nhau để tạo bối cảnh vô hướng. Nó đi xuống một câu hỏi về khả năng đọc.

Cá nhân tôi thích những điều sau đây:

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

Tôi thấy nó rõ ràng hơn

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

my $size = @array;
say $size;

Cái sau trông khá rõ ràng một mình như thế này, nhưng tôi thấy rằng dòng bổ sung mất đi sự rõ ràng khi một phần của mã khác. Nó hữu ích cho việc dạy những gì @arraylàm trong bối cảnh vô hướng và có thể nếu bạn muốn sử dụng $sizenhiều lần.


15
Cá nhân tôi thích phiên bản sử dụng từ khóa "vô hướng", bởi vì nó khá rõ ràng rằng nó buộc một bối cảnh vô hướng. my $size=@arrayCó vẻ như đó có thể là một sai lầm khi sử dụng sai sigil.
Nate CK

5
Đó là một ý tưởng thực sự tồi tệ. Những người sử dụng scalarkhông có lý do học bài học sai. Họ bắt đầu nhận được vào đầu rằng các nhà khai thác trả về các danh sách có thể được ép buộc vào vô hướng. Nhìn thấy nó hàng chục lần.
ikegami

2
Tại sao điều này "không có lý do"? Bạn đang sử dụng scalarbởi vì bạn đang ép danh sách vào một bối cảnh vô hướng. Đó là lý do đúng đắn để sử dụng nó. Ví dụ của bạn thực hiện chính xác điều tương tự, nhưng dựa vào những gì Perl làm khi bạn đánh giá một biến danh sách trong bối cảnh vô hướng ngầm. Do đó, ví dụ của bạn yêu cầu người đọc biết về hành vi ngầm của Perl trong bối cảnh đó. Bạn chỉ cần thêm một lớp hành vi ngầm vào biểu thức và Perl đã có quá nhiều hành vi ngầm mà bạn phải suy luận để giải mã một chương trình.
Nate CK

2
@Nate CK, Re "Tại sao điều này" không có lý do "? Bạn đang sử dụng scalarvì bạn đang ép danh sách vào một bối cảnh vô hướng", Bạn đã chứng minh quan điểm của tôi về việc học bài học sai. Điều này là hoàn toàn sai. Không có danh sách nào bị ép buộc bởi scalar. (Nếu nó đã làm, scalar(@array)scalar(@array[0..$#array])sẽ quay trở lại điều tương tự.) scalar(@array)Nói @arrayđể trả về một đại lượng vô hướng, mà bạn đã nói với nó để làm với my $size=.
ikegami

2
Tin hay không, các nhà phát triển phải gỡ lỗi mã được viết bởi các nhà phát triển khác. Và các nhà phát triển phải gỡ lỗi mã mà họ đã viết ba năm trước.
Nate CK

27

Điều này có được kích thước bằng cách buộc mảng vào bối cảnh vô hướng, trong đó nó được đánh giá là kích thước của nó:

print scalar @arr;

Đây là một cách khác để buộc mảng vào bối cảnh vô hướng, vì nó được gán cho một biến vô hướng:

my $arrSize = @arr;

Cái này lấy chỉ số của phần tử cuối cùng trong mảng, vì vậy nó thực sự có kích thước trừ 1 (giả sử các chỉ số bắt đầu từ 0, có thể điều chỉnh trong Perl mặc dù làm như vậy thường là một ý tưởng tồi):

print $#arr;

Cái cuối cùng này không thực sự tốt để sử dụng để lấy kích thước mảng. Sẽ rất hữu ích nếu bạn chỉ muốn lấy phần tử cuối cùng của mảng:

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

Ngoài ra, như bạn có thể thấy ở đây trên Stack Overflow, cấu trúc này không được xử lý chính xác bởi hầu hết các tô sáng cú pháp ...


2
Một sidenote: chỉ cần sử dụng $arr[-1]để có được phần tử cuối cùng. Và $arr[-2]để có được áp chót, và như vậy.
tuomassalo

1
@tuomassalo: Tôi đồng ý rằng đề xuất của bạn là một cách tiếp cận tốt hơn. Nhìn lại, $#arrkhông phải là một tính năng rất hữu ích và không phải ngẫu nhiên mà các ngôn ngữ khác không có nó.
Nate CK

6

Để sử dụng cách thứ hai, thêm 1:

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

for [0..$#array] { print $array[$_ ] } hoạt động thực sự tốt mặc dù nếu mục đích nhận được số lượng phần tử là lặp qua mảng. Ưu điểm là bạn có được phần tử cũng như bộ đếm được căn chỉnh.
Westrock

5

Cả ba đều cho cùng một kết quả nếu chúng ta sửa đổi cái thứ hai một chút:

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
Đây có phải là khác nhau bất cứ điều gì từ những gì đã được đề cập trong này câu trả lời và đây là một?
devnull

5

Thí dụ:

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

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

2

Các loại biến Perl của Perl Phần của tài liệu perlintro chứa

Biến đặc biệt $#arraycho bạn biết chỉ mục của phần tử cuối cùng của mảng:

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

Bạn có thể bị cám dỗ sử dụng $#array + 1để cho bạn biết có bao nhiêu mục trong một mảng. Đừng bận tâm. Khi điều đó xảy ra, việc sử dụng @arraynơi Perl mong đợi để tìm giá trị vô hướng (ngữ cảnh trong bối cảnh vô hướng) sẽ cung cấp cho bạn số lượng phần tử trong mảng:

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

Các tài liệu perldata cũng bao gồm này trong “giá trị vô hướng” phần .

Nếu bạn đánh giá một mảng trong ngữ cảnh vô hướng, nó sẽ trả về độ dài của mảng. (Lưu ý rằng điều này không đúng với danh sách, trả về giá trị cuối cùng, như toán tử dấu phẩy C, cũng như các hàm dựng sẵn, trả về bất cứ thứ gì chúng cảm thấy muốn trả về.) Điều sau luôn luôn đúng:

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

Một số lập trình viên chọn sử dụng một chuyển đổi rõ ràng để không có gì phải nghi ngờ:

$element_count = scalar(@whatever);

Trước đó trong cùng một phần tài liệu làm thế nào để có được chỉ mục của phần tử cuối cùng của một mảng.

Độ dài của một mảng là một giá trị vô hướng. Bạn có thể tìm thấy độ dài của mảng @daysbằng cách đánh giá $#days, như trong csh. Tuy nhiên, đây không phải là chiều dài của mảng; nó là chỉ số của phần tử cuối cùng, là một giá trị khác vì thông thường có phần tử thứ 0.


2

Có nhiều cách khác nhau để in kích thước của mảng. Dưới đây là ý nghĩa của tất cả: Hãy nói rằng mảng của chúng tôi làmy @arr = (3,4);

Cách 1: vô hướng

Đây là cách đúng để có được kích thước của mảng.

print scalar @arr;  # prints size, here 2

Phương pháp 2: Số chỉ mục

$#arrđưa ra chỉ số cuối cùng của một mảng. vì vậy nếu mảng có kích thước 10 thì chỉ số cuối cùng của nó sẽ là 9.

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

Chúng tôi đang thêm 1 ở đây xem xét mảng là 0-index . Nhưng, nếu nó không bằng 0 thì logic này sẽ thất bại .

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

Ví dụ trên in 6, vì chúng tôi đã đặt chỉ mục ban đầu của nó thành 4. Bây giờ chỉ mục sẽ là 5 và 6, với các yếu tố 3 và 4 tương ứng.

Cách 3:

Khi một mảng được sử dụng trong ngữ cảnh vô hướng, thì nó trả về kích thước của mảng

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

Thật ra phương pháp 3 và phương pháp 1 giống nhau.


2

Từ perldoc perldata , nên an toàn để trích dẫn:

Điều sau đây luôn đúng:

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

Chỉ cần bạn không $ # bất cứ điều gì ++ và tăng kích thước hoặc mảng của bạn một cách bí ẩn.

Các chỉ số mảng bắt đầu bằng 0.

Bạn có thể cắt một mảng xuống không có gì bằng cách gán danh sách null () cho nó. Sau đây là tương đương:

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

Điều này đưa tôi đến những gì tôi đang tìm kiếm đó là cách phát hiện mảng trống. Tôi đã tìm thấy nó nếu $ # trống == -1;


1

Điều gì về int(@array)nó như đe dọa đối số như vô hướng.


0

Để tìm kích thước của một mảng, sử dụng scalartừ khóa:

print scalar @array;

Để tìm ra chỉ mục cuối cùng của một mảng có $#(biến mặc định Perl). Nó đưa ra chỉ số cuối cùng của một mảng. Khi một mảng bắt đầu từ 0, chúng ta có được kích thước của mảng bằng cách thêm một vào $#:

print "$#array+1";

Thí dụ:

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

Đầu ra:

3

3
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.