นี่คือคำสั่ง perllol ที่สามารถเรียกใช้ในผู้ให้บริการโฮสต์ฟรีของ OnWorks โดยใช้เวิร์กสเตชันออนไลน์ฟรีของเรา เช่น Ubuntu Online, Fedora Online, โปรแกรมจำลองออนไลน์ของ Windows หรือโปรแกรมจำลองออนไลน์ของ MAC OS
โครงการ:
ชื่อ
perllol - การจัดการอาร์เรย์ของอาร์เรย์ใน Perl
DESCRIPTION
การประกาศ และ ทางเข้า of อาร์เรย์ of อาร์เรย์
โครงสร้างข้อมูลสองระดับที่ง่ายที่สุดในการสร้างใน Perl คืออาร์เรย์ของอาร์เรย์ บางครั้ง
ลวก ๆ เรียกรายการรายการ เข้าใจง่ายพอสมควร และเกือบ
ทุกอย่างที่ใช้ที่นี่จะมีผลบังคับใช้ในภายหลังด้วยข้อมูลนักเล่น
โครงสร้าง
อาร์เรย์ของอาร์เรย์เป็นเพียงอาร์เรย์ @AoA แบบเก่าทั่วไปที่คุณสามารถใช้สอง
ตัวห้อย เช่น $AoA[3][2] นี่คือการประกาศอาร์เรย์:
ใช้ 5.010; # เราจึงสามารถใช้ say()
# กำหนดให้กับอาร์เรย์ของเรา อาร์เรย์ของการอ้างอิงอาร์เรย์
@อ่าวเอ = (
[ "fred", "barney", "pebbles", "bambam", "dino", ],
[ "จอร์จ", "เจน", "เอลรอย", "จูดี้", ],
[ "โฮเมอร์", "บาร์ต", "มาร์จ", "แม็กกี้", ],
);
พูด $AoA[2][1];
บาร์ต
ตอนนี้คุณควรระวังให้มากว่าประเภทวงเล็บด้านนอกเป็นแบบกลมนั่นคือ a
วงเล็บ. นั่นเป็นเพราะคุณกำลังกำหนดให้กับ @array ดังนั้นคุณต้องมีวงเล็บ ถ้า
คุณต้องการที่นั่น ไม่ เพื่อเป็น @AoA แต่แทนที่จะอ้างอิงถึงมัน คุณสามารถทำได้
บางอย่างเช่นนี้:
# กำหนดการอ้างอิงไปยังอาร์เรย์ของการอ้างอิงอาร์เรย์
$ref_to_AoA = [
[ "fred", "barney", "pebbles", "bambam", "dino", ],
[ "จอร์จ", "เจน", "เอลรอย", "จูดี้", ],
[ "โฮเมอร์", "บาร์ต", "มาร์จ", "แม็กกี้", ],
];
พูด $ref_to_AoA->[2][1];
บาร์ต
โปรดสังเกตว่าประเภทวงเล็บด้านนอกมีการเปลี่ยนแปลง ดังนั้นไวยากรณ์การเข้าถึงของเราจึงเปลี่ยนไปด้วย
นั่นเป็นเพราะว่าไม่เหมือนกับ C ใน Perl คุณไม่สามารถแลกเปลี่ยนอาร์เรย์และการอ้างอิงได้อย่างอิสระ
ดังกล่าว $ref_to_AoA เป็นการอ้างอิงไปยังอาร์เรย์ ในขณะที่ @AoA เป็นอาร์เรย์ที่เหมาะสม
ในทำนองเดียวกัน $AoA[2] ไม่ใช่อาร์เรย์ แต่เป็นอาร์เรย์อ้างอิง เหตุใดคุณจึงเขียนสิ่งเหล่านี้ได้:
$เอโอเอ[2][2]
$ref_to_AoA->[2][2]
แทนที่จะต้องเขียนสิ่งเหล่านี้:
$AoA[2]->[2]
$ref_to_AoA->[2]->[2]
นั่นก็เพราะว่ากฎก็คือวงเล็บที่อยู่ติดกันเท่านั้น (ไม่ว่าจะเป็นสี่เหลี่ยมหรือหยัก)
คุณมีอิสระที่จะละเว้นลูกศร dereference ของตัวชี้ แต่คุณไม่สามารถทำเช่นนั้นได้
อันแรกถ้าเป็นสเกลาร์ที่มีการอ้างอิง ซึ่งหมายความว่า $ref_to_AoA always
ต้องการมัน
การเจริญเติบโต ของคุณ ของตนเอง
ทั้งหมดนั้นดีและดีสำหรับการประกาศโครงสร้างข้อมูลคงที่ แต่ถ้าคุณต้องการ
เพื่อเพิ่มองค์ประกอบใหม่ได้ทันที หรือสร้างขึ้นใหม่ทั้งหมดตั้งแต่เริ่มต้น
อันดับแรก มาดูการอ่านจากไฟล์กันก่อน นี้เหมือนกับการเพิ่มแถวที่a
เวลา. เราจะสมมติว่ามีไฟล์แบบแฟลตซึ่งแต่ละบรรทัดเป็นแถวและแต่ละคำ an
องค์ประกอบ. หากคุณกำลังพยายามพัฒนาอาร์เรย์ @AoA ที่มีสิ่งเหล่านี้ นี่คือสิ่งที่ถูกต้อง
วิธีทำ:
ในขณะที่ (<>) {
@tmp = แยก;
กด @AoA, [ @tmp ];
}
คุณอาจโหลดมาจากฟังก์ชัน:
สำหรับ $i (1 .. 10 ) {
$AoA[$i] = [ บางฟังก์ชั่น($i) ];
}
หรือคุณอาจมีตัวแปรชั่วคราวนั่งอยู่รอบ ๆ อาร์เรย์ในนั้น
สำหรับ $i (1 .. 10 ) {
@tmp = somefunc($i);
$AoA[$i] = [ @tmp ];
}
สิ่งสำคัญคือคุณต้องแน่ใจว่าใช้ตัวสร้างการอ้างอิงอาร์เรย์ "[ ]" นั่นเป็นเพราะ
สิ่งนี้จะไม่ทำงาน:
$AoA[$i] = @tmp; # ผิด!
เหตุผลที่ไม่ทำตามที่คุณต้องการก็เพราะว่าการกำหนดชื่ออาร์เรย์แบบนั้นให้กับa
สเกลาร์กำลังรับอาร์เรย์ในบริบทสเกลาร์ซึ่งหมายความว่าเพียงแค่นับจำนวน
องค์ประกอบใน @tmp
หากคุณอยู่ภายใต้ "ใช้อย่างเข้มงวด" (และถ้าคุณไม่ใช่ ทำไมในโลกนี้ไม่ใช่คุณ?)
คุณจะต้องเพิ่มคำประกาศเพื่อให้มีความสุข:
ใช้อย่างเข้มงวด
ของฉัน(@AoA, @tmp);
ในขณะที่ (<>) {
@tmp = แยก;
กด @AoA, [ @tmp ];
}
แน่นอน คุณไม่จำเป็นต้องมีอาร์เรย์ชั่วคราวเพื่อตั้งชื่อเลย:
ในขณะที่ (<>) {
กด @AoA [ แยก ];
}
ยังไม่ต้องใช้ ดัน (). คุณสามารถมอบหมายงานโดยตรงได้ถ้าคุณรู้
ที่คุณต้องการวางไว้:
ของฉัน (@AoA, $i, $line);
สำหรับ $i (0 .. 10 ) {
$line = <>;
$AoA[$i] = [ แยก " ", $line ];
}
หรือแม้แต่เพียงแค่
ของฉัน (@AoA, $i);
สำหรับ $i (0 .. 10 ) {
$AoA[$i] = [ แยก " ", <> ];
}
โดยทั่วไปแล้ว คุณควรใช้ฟังก์ชันที่อาจส่งคืนรายการใน
บริบทสเกลาร์โดยไม่ระบุอย่างชัดเจน สิ่งนี้จะชัดเจนยิ่งขึ้นสำหรับคนสบาย ๆ
ผู้อ่าน:
ของฉัน (@AoA, $i);
สำหรับ $i (0 .. 10 ) {
$AoA[$i] = [ แยก " ", สเกลาร์(<>) ];
}
หากคุณต้องการให้ตัวแปร $ref_to_AoA อ้างอิงถึงอาร์เรย์ คุณต้องทำ
บางอย่างเช่นนี้:
ในขณะที่ (<>) {
กด @$ref_to_AoA, [ แยก ];
}
คุณสามารถเพิ่มแถวใหม่ได้แล้ว แล้วการเพิ่มคอลัมน์ใหม่ล่ะ หากคุณกำลังเผชิญกับเพียงแค่
เมทริกซ์ มันมักจะง่ายที่สุดที่จะใช้การมอบหมายอย่างง่าย:
สำหรับ $x (1 .. 10) {
สำหรับ $y (1 .. 10) {
$AoA[$x][$y] = func($x, $y); $AoA[$x][$y] = ฟังก์ชัน($x, $y);
}
}
สำหรับ $x (3, 7, 9) {
$AoA[$x][20] += func2($x); $AoA[$x][XNUMX] += funcXNUMX($x); $AoA[$x][XNUMX] += ฟังก์ชั่นXNUMX($x);
}
ไม่สำคัญว่าองค์ประกอบเหล่านั้นมีอยู่แล้วหรือไม่ มันสร้างได้ด้วยความยินดี
ให้กับคุณ โดยตั้งค่าองค์ประกอบที่แทรกแซงเป็น "undef" ตามความจำเป็น
ถ้าคุณต้องการต่อท้ายแถว คุณต้องทำสิ่งที่ตลกกว่านี้เล็กน้อย:
# เพิ่มคอลัมน์ใหม่ให้กับแถวที่มีอยู่
ดัน @{ $AoA[0] }, "วิลมา", "เบ็ตตี้"; # ชัดเจน deref
ก่อนหน้า Perl 5.14 สิ่งนี้จะไม่คอมไพล์:
ดัน $AoA[0], "วิลมา", "เบ็ตตี้"; #โดยนัย deref
มาได้ยังไง? เพราะกาลครั้งหนึ่งการโต้เถียงกับ ดัน () ต้องเป็นอาร์เรย์จริงไม่ใช่
เป็นเพียงการอ้างอิงถึงหนึ่ง นั่นไม่เป็นความจริงอีกต่อไป อันที่จริงบรรทัดที่ระบุว่า "deref โดยนัย"
ด้านบนทำงานได้ดี - ในกรณีนี้ - เพื่อทำในสิ่งที่บอกว่า deref ชัดเจน
ที่บอกว่า "ในกรณีนี้" ก็เพราะว่า เพียง ใช้งานได้เพราะ $AoA[0] แล้ว
มีการอ้างอิงอาร์เรย์ หากคุณลองทำกับตัวแปรที่ไม่ได้กำหนด คุณจะรับ an
ข้อยกเว้น นั่นเป็นเพราะว่า dereference โดยปริยายจะไม่ทำให้ undefined กลายเป็นอัตโนมัติ
เปลี่ยนแปลงวิธีที่ "@{ }" จะ:
$aref ของฉัน = undef;
กด $aref, qw(ค่าอื่นๆ); # ผิด!
กด @$aref, qw(อีกสองสาม); # ตกลง
หากคุณต้องการใช้ประโยชน์จากพฤติกรรมการอ้างอิงโดยนัยใหม่นี้ ให้ดำเนินการทันที:
มันทำให้รหัสง่ายขึ้นบนตาและข้อมือ แค่เข้าใจว่ารุ่นเก่าจะทำให้สำลัก
บนมันในระหว่างการรวบรวม เมื่อใดก็ตามที่คุณใช้สิ่งที่ได้ผลเฉพาะในบางคน
ให้ปล่อย Perl และใหม่กว่า แต่ไม่ก่อนหน้านี้ คุณควรวางที่โดดเด่น
ใช้ v5.14; # จำเป็นสำหรับการ deref โดยปริยายของ array refs โดย array ops
directive ที่ด้านบนของไฟล์ที่ต้องการ ด้วยวิธีนี้เมื่อมีคนพยายามที่จะเรียกใช้
รหัสใหม่ภายใต้ Perl เก่าแทนที่จะได้รับข้อผิดพลาดเช่น
ประเภทของ arg 1 ที่จะพุชต้องเป็นอาร์เรย์ (ไม่ใช่องค์ประกอบอาร์เรย์) ที่ /tmp/a บรรทัดที่ 8 ใกล้ ""betty";
การดำเนินการของ /tmp/a ถูกยกเลิกเนื่องจากข้อผิดพลาดในการรวบรวม
จะได้รับแจ้งอย่างสุภาพว่า
ต้องใช้ Perl v5.14.0 -- นี่เป็นเพียง v5.12.3 เท่านั้น หยุดที่ /tmp/a บรรทัดที่ 1
BEGIN ล้มเหลว - การรวบรวมถูกยกเลิกที่ /tmp/a บรรทัดที่ 1
ทางเข้า และ การพิมพ์
ถึงเวลาพิมพ์โครงสร้างข้อมูลของคุณออกมาแล้ว คุณจะทำอย่างนั้นได้อย่างไร? ถ้า
คุณต้องการเพียงหนึ่งในองค์ประกอบ มันเป็นเรื่องเล็กน้อย:
พิมพ์ $AoA[0]][0];
ถ้าจะพิมพ์ให้ครบก็บอกไม่ได้
พิมพ์ @AoA; # ผิด
เพราะคุณจะได้รับเพียงรายการอ้างอิงและ Perl จะไม่อ้างอิงโดยอัตโนมัติ
สิ่งสำหรับคุณ คุณต้องม้วนตัวเองเป็นวงหรือสองรอบแทน นี้พิมพ์ทั้งหมด
โครงสร้างโดยใช้รูปแบบเปลือก สำหรับ() สร้างเพื่อวนรอบชุดด้านนอกของ
ตัวห้อย
สำหรับ $aref ( @AoA ) {
พูดว่า "\t [ @$aref ],";
}
หากคุณต้องการติดตามตัวห้อย คุณสามารถทำได้:
สำหรับ $i ( 0 .. $#AoA ) {
พูดว่า "\t elt $i คือ [ @{$AoA[$i]} ],";
}
หรือแม้กระทั่งสิ่งนี้ สังเกตวงใน
สำหรับ $i ( 0 .. $#AoA ) {
สำหรับ $j ( 0 .. $#{$AoA[$i]} ) {
พูดว่า "elt $i $j คือ $AoA[$i][$j]";
}
}
อย่างที่คุณเห็น มันซับซ้อนเล็กน้อย นั่นเป็นเหตุผลที่บางครั้งง่ายกว่าที่จะใช้
ชั่วคราวระหว่างทางผ่าน:
สำหรับ $i ( 0 .. $#AoA ) {
$aref = $AoA[$i];
สำหรับ $j ( 0 .. $#{$aref} ) {
พูดว่า "elt $i $j คือ $AoA[$i][$j]";
}
}
อืม... ยังน่าเกลียดอยู่เลย เกี่ยวกับเรื่องนี้:
สำหรับ $i ( 0 .. $#AoA ) {
$aref = $AoA[$i];
$n = @$aref - 1;
สำหรับ $j ( 0 .. $n ) {
พูดว่า "elt $i $j คือ $AoA[$i][$j]";
}
}
เมื่อคุณเบื่อที่จะเขียนงานพิมพ์แบบกำหนดเองสำหรับโครงสร้างข้อมูลของคุณ คุณอาจดูที่
โมดูล Dumpvalue มาตรฐานหรือ Data::Dumper อดีตคือสิ่งที่ดีบักเกอร์ Perl
ใช้ในขณะที่หลังสร้างรหัส Perl ที่แยกวิเคราะห์ได้ ตัวอย่างเช่น:
ใช้ v5.14; # ใช้ต้นแบบ + ใหม่ใน v5.14
รายการย่อย (+) {
ต้องการ Dumpvalue;
รัฐ $สวย = ใหม่ Dumpvalue::
ติ๊ก => q("),
compactDump => 1, # แสดงความคิดเห็นสองบรรทัดนี้
veryCompact => 1, # ถ้าคุณต้องการขนาดใหญ่กว่านี้
;
dumpValue $สวย @_;
}
# กำหนดรายการของการอ้างอิงอาร์เรย์ไปยังอาร์เรย์
@AoA ของฉัน = (
[ "เฟรด", "บาร์นีย์" ],
[ "จอร์จ", "เจน", "เอลรอย" ],
[ "โฮเมอร์", "มาร์จ", "บาร์ต" ],
);
ดัน $AoA[0], "วิลมา", "เบ็ตตี้";
แสดง @AoA;
จะพิมพ์ออกมา:
0 0..3 "เฟร็ด" "บาร์นีย์" "วิลมา" "เบ็ตตี้"
1 0..2 "จอร์จ" "เจน" "เอลรอย"
2 0..2 "โฮเมอร์" "มาร์จ" "บาร์ต"
ในขณะที่ถ้าคุณแสดงความคิดเห็นในสองบรรทัดที่ฉันบอกว่าคุณอาจต้องการก็จะแสดงให้คุณเห็น
วิธีนี้แทน:
0 อาร์เรย์(0x8031d0)
0 "เฟร็ด"
1 "บาร์นีย์"
2 "วิลมา"
3 "เบ็ตตี้"
1 อาร์เรย์(0x803d40)
0 "จอร์จ"
1 "เจน"
2 "เอลรอย"
2 อาร์เรย์(0x803e10)
0 "โฮเมอร์"
1 "มาร์จิ้น"
2 "บาร์ต"
ชิ้น
ถ้าคุณต้องการได้ชิ้น (ส่วนหนึ่งของแถว) ในอาร์เรย์หลายมิติ คุณจะต้อง
ต้องทำการสมัครรับข้อมูลแฟนซี นั่นเป็นเพราะในขณะที่เรามีคำพ้องความหมายที่ดีสำหรับ
องค์ประกอบเดียวผ่านลูกศรชี้สำหรับ dereference ไม่มีความสะดวกดังกล่าวสำหรับ
ชิ้น.
ต่อไปนี้เป็นวิธีดำเนินการหนึ่งรายการโดยใช้ลูป เราจะถือว่าตัวแปร @AoA เหมือนเดิม
@ส่วน = ();
$ x = 4;
สำหรับ ($y = 7; $y <13; $y++) {
กด @part, $AoA[$x][$y];
}
ลูปเดียวกันนั้นสามารถแทนที่ด้วยการดำเนินการสไลซ์:
@part = @{$AoA[4]}[7];
หรือเว้นระยะห่างเล็กน้อย:
@part = @{ $AoA[4] } [ 7..12 ];
แต่อย่างที่คุณอาจจินตนาการได้ การทำเช่นนี้อาจเป็นเรื่องยากสำหรับผู้อ่าน
อา แต่ถ้าคุณต้องการ สองมิติ ฝานเช่น มี $x รันจาก 4 และ $y
วิ่งจาก 7 ถึง 12? อืม... นี่เป็นวิธีง่ายๆ:
@newAoA = ();
สำหรับ ($startx = $x = 4; $x <= 8; $x++) {
สำหรับ ($starty = $y = 7; $y <= 12; $y++) {
$newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y]; $newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
}
}
เราสามารถลดการวนซ้ำบางส่วนผ่านชิ้น
สำหรับ ($x = 4; $x <= 8; $x++) {
กด @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ];
}
ถ้าคุณอยู่ใน Schwartzian Transforms คุณอาจจะเลือกแผนที่สำหรับสิ่งนั้น
@newAoA = แผนที่ { [ @{ $AoA[$_] } [ 7..12 ] ] } 4 .. 8;
แม้ว่าผู้จัดการของคุณจะกล่าวหาว่าคุณแสวงหาความมั่นคงในงาน (หรือความไม่มั่นคงอย่างรวดเร็ว) ผ่าน
รหัสที่ไม่สามารถเข้าใจได้ มันคงยากที่จะโต้แย้ง :-) ถ้าฉันเป็นคุณ ฉันจะใส่มันใน
ฟังก์ชั่น:
@newAoA = splice_2D( \@AoA, 4 => 8, 7 => 12 );
ประกบย่อย_2D {
$lrr ของฉัน = กะ; # อ้างอิงถึงอาร์เรย์ของการอ้างอิงอาร์เรย์!
ของฉัน ($x_lo, $x_hi,
$y_lo, $y_hi) = @_;
กลับแผนที่ {
[ @{ $lrr->[$_] } [ $y_lo .. $y_hi ] ]
} $x_lo .. $x_สวัสดี;
}
ใช้ perllol ออนไลน์โดยใช้บริการ onworks.net