Mảng kết hợp

8 94 0
Tài liệu đã được kiểm tra trùng lặp
Mảng kết hợp

Đang tải... (xem toàn văn)

Thông tin tài liệu

Mảng kết hợp Mảng kết hợp là gì? Mảng kết hợp cũng tựa nh mảng (kiểu danh sách) mà ta đã thảo luận trớc đây, trong đó nó là một tuyển tập các dữ liệu vô hớng, với các phần tử riêng đợc chọn ra bằng một giá trị chỉ số nào đó. Không giống mảng danh sách, giá trị chỉ số của mảng kết hợp không phải là số nguyên không âm nhỏ, mà thay vào đó là vô hớng tuỳ ý. Những vô hớng này (còn gọi là khoá) đợc dùng về sau để tìm kiếm các giá trị từ mảng này. Các phần tử của mảng kết hợp không có thứ tự đặc biệt. Bạn hãy xem chúng tựa nh bàn đầy những quân bài. Nửa trên của các con bài là khoá, còn nửa dới là giá trị của chúng. Mỗi lần bạn đặt một giá trị vào trong mảng kết hợp thì một con bài mới lại đợc tạo ra. Về sau khi bạn muốn sửa đổi giá trị này, bạn cho khoá, còn Perl tìm ra đúng con bài. Cho nên, thực sự, trật tự của các con bài là không quan trọng. Trong thực tế, Perl cất giữ các con bài (cặp khoá-giá trị) theo thứ tự bên trong đặc biệt để dễ dàng tìm ra một con bài đặc biệt, cho nên Perl không phải duyệt qua tất cả các cặp để tìm ra đúng con bài. Bạn không thể kiểm soát đợc trật tự này, cho nên đừng có thử. Biến mảng kết hợp Tên biến mảng kết hợp là dấu phần trăm (%) theo sau bởi một chữ, theo sau nữa là không hay nhiều chữ, chữ số và dấu gạch thấp. Nói cách khác, phần đi sau dấu phần trăm giống hệt cái mà chúng ta có cho tên biến vô hớng và biến mảng. Và giống nh chẳng có quan hệ gì giữa $fred và @fred, biến mảng kết hợp %fred cũng chẳng liên quan gì tới hai loại biến kia cả. Thay vì tham khảo tới toàn bộ mảng kết hợp, thông dụng hơn cả là ta tạo ra một mảng kết hợp và thâm nhập vào nó bằng cách tham khảo tới các phần tử của nó. Mỗi phần tử của mảng đều là một vô hớng tách biệt, đợc thâm nhập tới bởi một chỉ mục vô hớng, gọi là khoá. Các phần tử của mảng kết hợp %fred vậy đợc tham khảo đến bằng $fred{$key} với $key là bất kì biểu thức vô hớng nào. Lại chú ý rằng việc thâm nhập vào một phần tử của mảng không bắt đầu bằng cùng chỗ ngắt nh tên của toàn bộ mảng. Giống nh với mảng danh sách, bạn có thể tạo ra những phần tử mới bằng việc gán cho mảng một phần tử: $fred{aaa} = bbb ; # tạo ra khoá aaa, giá trị bbb $fred{234.5} = 456.7; # tạo ra khoá 234.5, giá trị 456.7 Hai câu lệnh này tạo ra hai phần tử trong mảng. Những tham khảo về sau tới cùng những phần tử này (dùng cùng khoá) sẽ cho lại giá trị đợc cất giữ. print $fred{aaa}; # in bbb $fred{234.5} += 3; # làm cho nó thành 459.7 Việc tham khảo tới một phần tử không có sẵn sẽ cho lại giá trị undef, giống nh với mảng danh sách hay biến vô hớng không xác định. Biểu diễn hằng kí hiệu cho mảng kết hợp Bạn có thể muốn thâm nhập vào mảng kết hợp nh một toàn thể, để hoặ khởi đầu nó hay sao chép nó sang mảng kết hợp khác. Perl không thực sự có biểu diễn hằng kí hiệu cho mảng kết hợp, cho nên thay vì thế nó tháo rời mảng ra nh một danh sách. Mỗi cặp phần tử trong danh sách (mà bao giờ cũng phải có một số chẵn phần tử) đều xác định ra một khoá và giá trị tơng ứng của nó. Biểu diễn tháo rời này có thể đợc gán vào trong mảng kết hợp khác, mà rồi sẽ tái tạo lại cùng mảng kết hợp đó. Nói cách khác: @fred_list = %fred; # @fred_list nhận (aaa, bbb, 234.5, 456.7) %barney = @fred_list; # tạo ra %barney giống %fred %barney = %fred; # cách nhanh hơn để làm cùng việc đó %smooth = (aaa, bbb, 234.5, 456.7); # tạo ra %smooth giống nh %fred, từ các giá trị hằng kí hiệu Trật tự của các cặp khoá-giá trị là tuỳ ý trong cách biểu diễn tháo rời này, và không thể kiểm soát đợc. Cho dù bạn có tráo đổi một số giá trị và tạo ra một mảng nh một toàn thể thì danh sách tháo rời thu đợc vẫn cứ theo bất kì trật tự nào mà Perl đã tạo ra để thâm nhập hiệu quả vào các phần tử riêng. Bạn đừng bao giờ nên dựa trên bất kì trật tự đặc biệt nào. Các toán tử mảng kết hợp Sau đây là một số toán tử cho mảng kết hợp. Toán tử keys() Toán tử keys(%tên mảng) cho lại danh sách các tất cả các khoá hiện có trong mảng kết hợp %tên mảng . Nói cách khác, nó tựa nh các phần tử đợc đánh số lẻ (một, ba năm vân vân) của danh sách đợc việc tháo rời %tên mảng cho lại trong ngữ cảnh mảng, và trong thực tế, cho lại chúng theo trật tự đó. Nếu không có phần tử nào trong mảng kết hợp thì keys() cho lại một danh sách rỗng. Chẳng hạn, bằng việc dùng mảng kết hợp từ thí dụ trớc: $fred{aaa} = bbb; $fred{234.5} = 456.7; @list = keys(%fred) ; # @list nhận đợc (aaa, 234.5) hay (234.5, aaa) Các dấu ngoặc tròn là tuỳ chọn: keys %fred cũng giống nh keys(%fred). foreach $key (key %fred) {# một lần cho mỗi khoá của %fred print tại $key chúng ta có $fred{$key}\n; # in khoá và giá trị } Thí dụ này cũng chỉ ra rằng các phần tử mảng kết hợp có thể chen lẫn nhau trong các xâu nháy kép. Tuy nhiên bạn không thể xen lẫn toàn bộ mảng * . Trong ngữ cảnh vô hớng, toán tử keys() cho lại số các phần tử (cặp khoá-giá trị) trong mảng kết hợp. Chẳng hạn, bạn có thể tìm ra liệu mảng kết hợp có rỗng hay không: if (keys(%mảng nào đó)) { # nếu keys() khác không: .; # mảng là khác rỗng } # . hoặc . while (keys(%mảng nào đó) < 10) { . ; # cứ lặp chu trình khi ta có ít hơn 10 phần tử } Toán tử values() Toán tử values(%tên mảng) cho lại một danh sách tất cả các giá trị hiện tại của %tên mảng, theo cùng trật tự nh các khoá đợc toán tử keys(%tên mảng) cho lại. Nh với keys(), các dấu ngoặc tròn là tuỳ chọn. Chẳng hạn: %lastname = (); # buộc %lastname là rỗng $lastname(fred} = flintstore; $lastname{barney} = rubble; @lastname = values(%lastname); # lấy các giá trị Tại điểm này @lastname chứa hoặc (flintstore, rubble) hay đảo ngợc của nó. Toán tử each() Nếu bạn muốn lặp trên (tức là xem xét mọi phần tử của) toàn bộ mảng kết hợp, thì bạn có thể dùng keys(), duyệt xét từng khoá đợc cho lại và nhận giá trị tơng ứng. Trong khi phơng pháp này thờng hay đợc dùng, một cách hiệu quả hơn là dùng each(%tên mảng), toán tử sẽ cho lại cặp khoá-giá trị nh một danh sách hai phần tử. Với mỗi lần thực hiện toán tử này cho cùng mảng, cặp khoá-giá trị kế tiếp sẽ đợc cho lại, cho tới khi tất cả các phần tử đều đã đợc thâm nhập tới. Khi không còn cặp nào nữa thì each() cho lạimột danh sách rỗng. Vậy chẳng hạn, để bớc qua mảng %lastname trong thí dụ trớc, hãy làm điều gì đó tựa nh thế này: while (($first, $last) = each(%lastname)) { print Tên cuối cùng của $first là $last\n; } * * Này, bạn có thể đấy, bằng cách dùng lát cắt, nhng chúng ta không nói về lát cắt ở đây. Việc gán một giá trị mới cho toàn bộ mảng sẽ đặt lại từng toán tử each() cho từ đầu. Việc bổ sung hay loại bỏ các phần tử của mảng thì rất có thể gây ra lẫn lộn each() (và có thể gây lẫn lộn cho cả bạn nữa). Toán tử delete Cho đến giờ, với điều bạn biết đợc, bạn có thể thêm phần tử vào mảng kết hợp, nhng bạn không thể loại bỏ chúng (một việc khác hơn là gán giá trị mới cho toàn bộ mảng). Perl cung cấp toán tử delete để loại bỏ các phần tử. Toán hạng của delete là một tham khảo mảng kết hợp, hệt nh nếu bạn chỉ nhìn vào một giá trị đặc biệt. Perl loại bỏ cặp khoá-giá trị khỏi mảng kết hợp, và cho lại giá trị của phần tử bị xoá. Chẳng hạn: %fred = (aaa, bbb, 234.5, 34.56) ; # cho %fred 2 phần tử delete $fred{aaa}; # %fred bây giờ chỉ còn một cặp khoá-giá trị Bài tập Xem phụ lục A về lời giải. 1. Hãy viết một chơng trình đọc và in một xâu và giá trị ánh xạ của nó tơng ứng với ánh xạ đợc trình bầy trong bảng sau: Cái vào Cái ra đỏ lục xanh táo lá đại dơng 2. Hãy viết một chơng trình đọc một chuỗi các từ với một từ trên dòng cho tới cuối tệp, rồi in ra một tóm tắt có bao nhiêu lần mỗi từ đã gặp. (Thêm một thách thức, hãy sắp xếp các từ theo thứ tự giảm dần mã ASCII khi đa ra.) 6 Vào / ra cơ bản Vào từ STDIN Việc đọc từ lối vào chuẩn (qua bộ khiển giải Perl đợc gọi là STDIN) thì thật dễ dàng. Chúng ta đã làm việc này với toán tử <STDIN>. Việc tính toán tử này trong ngữ cảnh vô hớng cho bạn một dòng tiếp của cái vào, hay undef nếu không còn dòng nào nữa, giống nh: $a = <STDIN>; # đọc dòng tiếp Việc tính toán tử này trong ngữ cảnh mảng sẽ cho bạn tất cả các dòng còn lại nh một danh sách - mỗi phần tử của danh sách này là một dòng, bao gồm các kết thúc dòng mới của nó. Chúng ta đã thấy điều này trớc đây, nhng xem nh việc làm mới lại, nó có thể trông nh một cái gì đó tựa nh thế này: @a = <STDIN>; Một cách điển hình, một trong những điều bạn muốn làm là đọc tất cả các dòng một lúc, và làm điều gì đó trên mỗi dòng. Một cách chung để làm điều này là: while ($_ = <STDIN>) { # xử lí $_ tại đây (cho từng dòng) } Cứ mỗi khi một dòng đợc đọc vào, <STDIN> lại cho một giá trị đúng * , cho nên chu trình tiếp tục thực hiện. Khi <STDIN> không còn dòng nào để đọc nữa thì nó cho lại undef , cho giá trị sai, kết thúc chu trình. Việc đọc một giá trị vô hớng cho <STDIN> và dùng giá trị đó làm biểu thức điều khiển cho chu trình (nh trong thí dụ trớc) thờng hay xuáat hiện đến mức Perl có hẳn một cáhc viết tắt cho nó. Bất kì khi nào việc kiểm thử chu trình chỉ bao gồm một toán tử đa vào (cái gì đó tựa nh < .>), thì Perl tự động sao dòng đợc đọc vào trong biến $_. while ($_ = <STDIN>) { # giống while ($_ = <STDIN>) chop; # giống chop($_) # các phép toán khác với $_ ở đây } * * Nếu dòng cuối cùng của tệp chỉ có môt jksi tự 0 thì <STDIN> cho lại undef tại dòng đó; thay vì tại cuối tệp. Nếu bạn tạo ra một tệp giống nh thế thì ngời lập trình Perl trên toàn thế giới sẽ gửi cho bạn th giận dỗi. Nhng đó là một tệp bệnh hoạn làm phá vỡ việc dùng loại chu trình này. Trong chơng này: Vào từ STDIN Vào từ toán tử Diamond Đa ra STDOUT Vì biến $_ là mặc định cho nhiều phép toán nên bạn có thể tiết kiệm khá nhiều về việc gõ theo cách này. Đa vào từ toán tử hình thoi Một cách khác để đọc cái vào là dùng toán tử hình thoi: <>. Toán tử này giống nh <STDIN> ở chỗ nó cho lại một dòng riêng lẻ trong ngữ cảnh vô hớng (với undef nếu tất cả các dòng này đã đợc đọc), hay tất cả các dòng còn lại nếu đợc dùng trong ngữ cảnh mảng. Tuy nhiên, khác với <STDIN>, toán tử hình thoi lấy dữ liệu từ tệp hay các tệp đợc xác định trên dòng lệnh đợc gọi trong chơng trình Perl. Chẳng hạn, nếu bạn có một chơng trình mang tên kitty, bao gồm: #! /usr/bin/perl while (<>) { print $_; } và nếu bạn gọi kitty với: kitty file1 file2 file3 thì toán tử hình thoi sẽ đọc từng dòng của file1 theo sau bởi từng dòng của file2 và file3 lần lợt, cho lại undef khỉ khi tất cả các dòng đã đợc đọc hết. Nh bạn có thể thấy, kitty làm việc giống nh cat, gửi tất cả các dòng của tệp có tên ra lối ra chuẩn theo tuần tự. Nếu, giống cat, bạn không xác định bất kì tên tệp nào trên dòng lệnh thì toán tử hình thoi sẽ tự động đọc từ lối vào chuẩn. Về mặt kĩ thuật, toán tử hình thoi không nhìn y nguyên vào các đối dòng lệnh - nó làm việc từ mảng @ARGV. Mảng này là một mảng đặc biệt đợc bộ thông dịch Perl đặt sẵn là một danh sách các đối dòng lệnh. Mỗi đối dòng lệnh lại bị bỏ đi sau khi Perl đã lấy các chuyển mạch dòng lệnh của nó để đa vào một phần tử tách biệt của mảng @ARGV. Bạn có thể hiểu danh sách này theo bất kì cách nào bạn muốn * . Bạn thậm chí có thể đặt mảng này bên trong chơng trình của mình, và có toán tử hình thoi làm việc trên danh sách mới thay vì các đối dòng lệnh, nh thế này: @ARGV = (aaa, bbb, ccc); while (<>) { # xử lí tệp aaa, bbb và ccc print Dòng này là: $_; } Trong Chơng 10, Giải quyết tệp và kiểm thử tệp, chúng ta sẽ thấy cách mở và đóng các tệp xác định vào thời điểm xác định, nhng kĩ thuật này đã đợc dùng cho một số chơng trình nhanh-và-bẩn của tôi. * * Th viện chuẩn của Perl chứa các trình cho việc phân tích kiểu nh getop cho các đối dòng lệnh của chơng trình Perl. Xam Sách con lừa để biết thêm thông tin về th việc này. Đa ra STDOUT Perl dùng các toán tử print và printf để ghi lên lối ra chuẩn. Ta hãy xem cách chúng đợc dùng. Dùng print cho đa ra thông thờng Chúng ta đã dùng print để hiển thị văn bản lên lối ra chuẩn. Ta hãy mở rộng thêm một chút. Toán tử print nhận một danh sách các xâu, và gửi lần lợt từng xâu ra lối ra chuẩn, không can thiệp hay thêm các kí tự vào đuôi. Điều có thể không hiển nhiên là ở chỗ print thực sự chỉ là toán tử danh sách, và cho lại một giá trị giống nh bất kì toán tử danh sách nào khác. Nói cách khác: $a = print (xin chào, mọi ngời, \n) ; sẽ là một cách khác để nói xin chào mọi ngời. Giá trị cho lại của print là một giá trị đúng hay sai, chỉ ra sự thành công của việc in. Nó gần nh bao giờ cũng thành công, trừ phi bạn gặp lỗi vào/ra nào đó, cho nên $a trong trờng hợp này sẽ gần nh bao giờ cũng là 1. Đôi khi, bạn sẽ cần bổ sung thêm các dấu ngoặc vào print nh đợc nêu trong thí dụ này, đặc biệt nếu điều đầu tiên bạn muốn in bắt đầu với một dấu mở ngoặc tròn, nh trong: print (2+3), xin chào; # sai! in 5, bỏ qua xin chào print ((2+3), xin chào); # đúng! in 5xin chào print 2+3, xin chào; # cũng đúng! in 5xin chào Dùng printf cho cái ra có định dạng Bạn có thể muốn có một chút ít kiểm soát với cái ra hơn là khả năng print cung cấp. Trong thực tế, bạn có thể quen với cái ra có định dạng của hàm printf của C. Chớ có sợ - Perl cung cấp một phép toán tơng ứng với cùng tên. Toán tử printf nhận một danh sách đối (đợc bao trong dấu ngoặc tròn tuỳ chọn, nh toán tử print). Đối thứ nhất là một xâu kiểm soát định dạng, xác định cách in các đối còn lại. Nếu bạn còn cha quen thuộc với hàm printf chuẩn, thì bạn nên kiểm tra xem lại hàm printf. Tuy nhiên, xem nh một thí dụ: printf %15s %5d %10.2f\n, $s, $n, $r; sẽ in ra $s trong một trờng 15 kí tự, rồi đến dấu cách, rồi đến $n xem nh một số nguyên trong trờng 5 kí tự, ròi đến môt jdấu cách khác, đến $r nh giá trị dấu phẩy động với 2 vị trí thập phân trong một trờng 10 kí tự, và cuối cùng là một dấu dòng mới. Bài tập Xem Phụ lục A về lời giải. 1. Hãy viết một chơng trình hành động nh cat, nhng đảo ngợc thứ tự các dòng. (Một số hệ thống có tiện ích kiểu nh vậy mang tên tac.) 2. Hãy viết một chơng trình đọc một danh sách các xâu rồi in ra xâu trong một cột có căn lề phải 20 kí tự. Chẳng hạn, đa vào xin chào, tạm biệt in ra xin chào và tạm biệt đợc căn lề phải trong cột 20 kí tự. 3. Hãy sửa đổi chơng trình của bài tập trớc để cho phép ngời dùng chọn lấy chiều rộng cột. Chẳng hạn, đa vào 20, xin chào và tạm biệt cũng làm cùng việc nh chơng trình trớc đã làm, nhng đa vào 30, xin chào và tạm biệt thì phải căn lề xin chào và tạm biệt theo cột 30 kí tự. . Mảng kết hợp Mảng kết hợp là gì? Mảng kết hợp cũng tựa nh mảng (kiểu danh sách) mà ta đã thảo luận trớc đây,. tử mảng kết hợp Sau đây là một số toán tử cho mảng kết hợp. Toán tử keys() Toán tử keys(%tên mảng) cho lại danh sách các tất cả các khoá hiện có trong mảng

Ngày đăng: 28/09/2013, 10:20

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan