หาขนาดของอาร์เรย์ใน 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

ใน scalar context; @arr ส่งคืนขนาดตาราง $ x = @ arr เป็นบริบทสเกลาร์ $ # arr ส่งคืนดัชนีสุดท้ายของอาร์เรย์ การสร้างดัชนีเริ่มต้นที่ 0 ดังนั้นจึงเป็นสมการที่แท้จริง $ # arr + 1 == @arr หากคุณเขียนบางองค์ประกอบที่ไม่เป็นไปตามปกติตัวอย่างเช่น $ arr [100] = 'any' ตารางจะถูกเพิ่มเป็นดัชนีสูงสุดสูงสุด 100 โดยอัตโนมัติและ (รวมถึงดัชนี 0) ถึงองค์ประกอบ 101 รายการ
Znik

คำตอบ:


234

วิธีแรกและวิธีที่สามเหมือนกัน: พวกเขาประเมินอาร์เรย์ในบริบทสเกลาร์ ฉันคิดว่านี่เป็นวิธีมาตรฐานในการรับขนาดของอาร์เรย์

วิธีที่สองส่งคืนดัชนีสุดท้ายของอาร์เรย์ซึ่งไม่เหมือนกับขนาดอาร์เรย์


29
ขนาดของ (1,2,3) คือ 3 และดัชนีคือ (โดยค่าเริ่มต้น) 0, 1 และ 2 ดังนั้น $ # arr จะเป็น 2 ในกรณีนี้ไม่ใช่ 3
Nate CK

5
ตัวแปรที่กำหนดไว้ล่วงหน้า$[ระบุ "ดัชนีขององค์ประกอบแรกในอาร์เรย์และของอักขระตัวแรกในสตริงย่อย" ( perldoc perlvar) มันถูกตั้งค่าเป็น 0 โดยค่าเริ่มต้นและการตั้งค่าเป็นสิ่งอื่นที่ไม่ใช่ 0 นั้นเป็นกำลังใจอย่างมาก
Keith Thompson

5
@ Keith Thompson $[เป็นกำลังใจ (และได้รับสำหรับทศวรรษ) $[เลิกใช้แล้ว การใช้$[ปัญหาคำเตือนการเลิกใช้แม้ว่าจะไม่ได้เปิดการเตือน การมอบหมายอะไรก็ได้ แต่ศูนย์ให้$[เป็นข้อผิดพลาดใน 5.16 เราหยุดพูดถึง$[แล้วได้ไหม?
ikegami

2
@ Keith Thompson ที่อายุมากกว่า 5.14 จริง แต่อย่างที่ฉันบอกว่ามันเป็นกำลังใจและเลิกใช้ไปนานกว่านั้นและบางคนที่ใช้$[ก็จะรู้ถึงผลกระทบของมัน
ikegami

7
@ikegami: ใช่ แต่มีคนพยายามเข้าใจความแตกต่างระหว่างscalar @arrและ$#arrควรยังคงเข้าใจถึงผลกระทบที่เป็นไปได้ของ$[หายากแม้ว่าพวกเขาจะเป็น
Keith Thompson

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 ในบริบทนั้น คุณเพิ่งเพิ่มเลเยอร์พฤติกรรมอีกนัยหนึ่งให้กับนิพจน์และ 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
sidenote: ใช้$arr[-1]เพื่อรับองค์ประกอบสุดท้าย และ$arr[-2]เพื่อให้ได้ผลสุดท้ายและอื่น ๆ
tuomassalo

1
@tuomassalo: ฉันเห็นด้วยว่าข้อเสนอแนะของคุณเป็นวิธีที่ดีกว่า ในการหวนกลับ$#arrไม่ได้เป็นคุณสมบัติที่มีประโยชน์มากและไม่มีอุบัติเหตุที่ภาษาอื่นไม่มี
Nate CK

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 () ให้กับมัน สิ่งต่อไปนี้เทียบเท่า:

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

ซึ่งนำฉันไปยังสิ่งที่ฉันกำลังมองหาซึ่งเป็นวิธีการตรวจสอบอาร์เรย์ว่างเปล่า ฉันพบว่าถ้า $ # ว่าง == -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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.