วิธีคิดแบบนักวิทยาการคอมพิวเตอร์/Lists
บทที่ 8 Lists
[แก้ไข | แก้ไขต้นฉบับ]List คือ ชุดของค่า ที่ซึ่งแต่ละค่าถูกค้นพบด้วย index ค่าที่ถูกสร้างขึ้นเป็น list จะเรียกว่า elements
List คล้ายกันกับ strings ซึ่งเป็นชุดของตัวอักษร นอกจากนี้ elements ของ list นั้น สามารถมี typeได้ทุกแบบ Lists และ strings – และสิ่งที่นอกจากนี้ที่ทำตัวเหมือนกันกับ ชุดของการจัดเรียง – เรียกว่า sequences
8.1 List values
[แก้ไข | แก้ไขต้นฉบับ]มีหลากหลายทางที่จะสร้าง list ขึ้นมาใหม่; ที่ง่ายที่สุดคือ ล้อมค่า elements ในวงเล็บสี่เหลี่ยม ([ and ]):
[10, 20, 30, 40]
[“spam”, “bungee”, “swallow”]
ตัวอย่างแรกคือ list ของ integers(ข้อมูลชนิดตัวเลขจำนวนเต็ม)สี่ตัว ตัวอย่างที่สองคือ list ของ strings (ข้อมูลชนิดข้อความ) Elements ของ list ไม่จำเป็นต้องมี type แบบเดียวกัน List ต่อไปนี้ประกอบด้วย string, float, integer, และ list อีกตัวหนึ่ง:
[“hello”, 2.0, 5, [10, 20]]
List ที่อยู่ภายใน list จะถูกกล่าวว่าเป็น nested
List ที่ประกอบด้วย จำนวนเต็มที่ต่อเนื่องตามลำดับนั้นธรรมดา Python ให้วิธีการง่ายๆในการสร้างมัน:
>>> rang (1,5)
[1, 2, 3, 4]
Function range มีสอง argument และ return list ที่ประกอบด้วยตัวเลขจำนวนเต็มทั้งหมดจาก argument ตัวแรกถึงตัวสุดท้าย รวมตัวแรกแต่ไม่รวมถึงตัวเลขที่เป็น argument ตัวที่สอง!
มีอีกสองรูปแบบของ range ด้วย argument เพียงตัวเดียว มันสร้าง list ที่เริ่มต้นจาก 0:
>>> range(10)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
ถ้ามี argument ตัวที่สาม มันกำหนดช่องว่างระหว่างค่าที่ต่อเนื่องกัน, ซึ่งเรียกว่า step size ตัวอย่างนี้นับจาก 1 ถึง 10 ด้วยระยะก้าวคือ 2:
>>> rang(1,10,2)
[1, 3, 5, 7, 9]
โดยสรุป มี list พิเศษที่ไม่ได้ประกอบด้วย element มันถูกเรียกว่า empty list และมันหมายถึง []
ด้วยวิธีการเหล่านี้ในการสร้าง list มันจะน่าผิดหวัง ถ้าเราไม่สามารถกำหนดค่า list เป็นตัวแปรหรือส่ง list เป็น parameter สู่ functions. เราสามารถทำได้
vocabulary = [“ameliorate”, “castigate”, “defenstrate”]
numbers = [17, 123]
empty = []
print vocabulary, numbers, empty
[“ameliorate”, “castigate”, “defenstrate”] [17, 123] []
8.2 Accessing elements
[แก้ไข | แก้ไขต้นฉบับ]Syntax สำหรับการเข้าถึง elements ของ list คือ syntax เดียวกันกับการเข้าถึง characters(ข้อมูลชนิดอักขระ) ของ string – สัญลักษณ์วงเล็บ ([]) expression ภายในวงเล็บกำหนด index จำไว้ว่า indices เริ่มต้นจาก 0:
print number[0]
numbers[1] = 5
สัญลักษณ์วงเล็บ สามารถปรากฏได้ทุกที่ใน expression เมื่อมันปรากฏขึ้นในทางข้างซ้ายของการกำหนดค่ามันเปลี่ยนแปลงหนึ่งใน element ของ list นั้น ดังนั้น element ตัวที่ 1-eth ซึ่งเคยเป็น 123 ตอนนี้คือ 5
integer expression ใดๆ สามารถใช้เป็น index ได้:
>>> number[3-2]
5
>>> number[1.0]
TypeError: sequence index must be integer
ถ้าคุณลองอ่านหรือลองเขียน element ซึ่งไม่ได้มีอยู่ คุณก็จะได้ runtime error:
>>> numbers[2] = 5
IndexError: list assignment index out of range
ถ้า index เป็นค่าลบ มันจะนับถอยหลังจากตัวสุดท้ายของ list:
>>> numbers[-1]
5
>>> numbers[-2]
17
>>> numbers[-3]
IndexError: list index out of range
numbers[-1] คือ element ตัวสุดท้ายของ list numbers[-2] คือ element ตัวสองตัวก่อนสุดท้ายของ list, และ numbers[-3] ไม่ได้มีอยู่
มันธรรมดาที่ใช้ตัวแปร loop เป็น list index
horsemen = [“war”, “famine”, “pestilence”, “death”]
i = 0
while i < 4:
print horsemen[i]
i = i + 1
loopนี้นับจาก 0 ถึง 4 เมื่อตัวแปร loop i คือ 4 เงื่อนไขผิดพลาดและ loop สิ้นสุด ดังนั้น body ของ loop จะทำการดำเนินการเพียงเมื่อ i คือ 0, 1, 2, และ 3
แต่ละครั้งที่เข้าไปใน loop ตัวแปร i ถูกใช้เป็น index เข้าไปใน list ทำการ print i-eth element รูปแบบการคำนวณแบบนี้เรียกว่า list traversal
8.3 List length
[แก้ไข | แก้ไขต้นฉบับ]function len จะ return ค่าความยาวของ list. มันเป็นความคิดที่ดีที่จะใช้ค่านี้แทนค่าคงที่ วิธีนั้น ถ้าขนาดของ list เปลี่ยนไป คุณไม่ต้องตรวจสอบโปรแกรมโดยการเปลี่ยน loop ทั้งหมด; มันจะทำงานอย่างถูกต้องสำหรับ list ทุกๆขนาด:
horsemen = [“war”, “famine”, “pestilence”, “death”]
while i < len(horsemen):
print horsemen[i]
i = i + 1
ในครั้งสุดท้ายของ loop ที่ถูกดำเนินการ i คือ len(horsemen) – 1 ซึ่งเป็น index ของ element ตัวสุดท้าย. เมื่อ i เท่ากับ len(horsemen) เงื่อนไขจะล้มเหลวและ body จะไม่ถูกดำเนินการ ซึ่งเป็นสิ่งที่ดี เนื่องจาก len(hoesemen) ไม่ได้เป็น index ที่ถูกต้อง
ถึงแม้ว่า list สามารถประกอบไปด้วย list อื่นๆ list ที่อยู่ภายในยังคงนับว่าเป็น element ตัวหนึ่งๆ ความยาวของ list นี้คือ 4:
[‘spam!’, 1, [‘Brie’, ‘Roquefort’, ‘Pol le Veq’], [1, 2, 3]]
8.4 List membership
[แก้ไข | แก้ไขต้นฉบับ]in เป็น boolean operator ซึ่งตรวจสอบสมาชิกในลำดับ. เราเคยใช้มันใน หมวด 7.10 กับ strings แต่มันทำงานเช่นเดียวกันกับ list และ sequence อื่นๆ:
>>> horsemen = [“war”, “famine”, “pestilence”, “death”]
>>> ‘pestilence’ in horsemen
True
>>> ‘debauchery’ in horsemen
False
“pestilence” เป็นสมาชิกของ horsemen list, in operator จะ return ค่า true. “debauchery” ไม่ได้อยู่ใน list, in return ค่า false
เราสามารถใช้ not รวมกันกับ in เพื่อตรวจสอบว่า element ไหนที่ไม่ได้เป็นสมาชิกของ list:
>>> ‘debauchery’ not in horsemen
True
8.5 List and for loops
[แก้ไข | แก้ไขต้นฉบับ]for loop ที่เราเห็นกันไปในหมวดที่ 7.3 ทำงานร่วมกับ lists ได้เช่นเดียวกัน. โดยทั่วๆปิ syntax ของ for loop คือ:
for VARIABLE in LIST:
BODY
Statement นี้จะมีค่าเท่ากันกับ:
i = 0
while i < len(LIST):
VARIABLE = LIST[i]
BODY
i = i + 1
for loop จะสั้นและได้ใจความมากกว่าเนื่องจากเราสามารถตัดตัวแปร loop ออกไปได้ i.
นี่คือ loop ที่ได้กล่าวมาข้างต้น ซึ่งเขียนด้วย for loop
for horseman in horsemen:
print horseman
มันแทบจะอ่านเหมือนในภาษาอังกฤษ:
“For (every) horseman in (the list of) horsemen, print (the name of the) horseman”
list expression ใดๆก็สามารถใช้ใน for loop ได้:
for number in range(20):
if number % 2 == 0:
print number
for fruit in [“banana”, “apple”, “quince”]:
print “I like to eat” + fruit + “s!”
ตัวอย่างแรก แสดงเลขคู่ทั้งหมดระหว่าง 0 และ 19 ตัวอย่างที่สองแสดงเป็นคำพูดแสดงความสนใจสำหรับผลไม้หลากหลายชนิด
8.6 List operations
[แก้ไข | แก้ไขต้นฉบับ]สัญลักษณ์ + ใช้เชื่อมต่อ lists เข้าด้วยกัน:
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = a + b
>>> print c
[1, 2, 3, 4, 5, 6]
ในทำนองเดียวกัน สัญลักษณ์ * กระทำซ้ำ list:
>>> [0] * 4
[0, 0, 0, 0]
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
ตัวอย่างแรกกระทำซ้ำกับ [0] 4ครั้ง ตัวอย่างที่สอง กระทำซ้ำกับ [1, 2, 3] 3ครั้ง
8.7 List slices
[แก้ไข | แก้ไขต้นฉบับ]การ slice ที่เราได้เห็นในหมวดที่ 7.4 ทำงานร่วมกับ list ได้เช่นเดียวกัน:
>>> list = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
>>> list [1:3]
[‘b’, ‘c’]
>>> list [:4]
[‘a’, ‘b’, ‘c’, ‘d’]
>>> list[3:]
[‘d’, ‘e’, ‘f’]
ถ้าคุณเว้น index ตัวแรก slice จะเริ่มต้นตั้งแต่แรก ถ้าคุณเว้น index ตัวที่สอง slice จะไปยังท้ายสุด ดังนั้นถ้าคุณเว้นว่างไว้ทั้งสองตัว slice จะทำการคัดลอก list ทั้งหมด
>>> list[:]
[‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
8.8 List are mutable
[แก้ไข | แก้ไขต้นฉบับ]ไม่เหมือนกับ strings lists เปลี่ยนแปลงได้ ซึ่งหมายถึงเราสามารถเปลี่ยน elements ของมันได้ โดยใช้สัญลักษณ์วงเล็บ ทางด้านซ้ายของกี่กำหนดค่า เราสามารถอัพเดทหนึ่งใน elements:
>>> fruit = [“banana”, “apple”, “quince”]
>>> fruit [0] = “pear”
>>> fruit [-1] = “orange”
>>> print fruit
[“pear”, “apple”, “orange”]
ด้วย slice operator เราสามารถอัพเดท element หลายๆตัวในครั้งเดียว:
>>> list = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
>>> list[1:3] = [‘x’, ‘y’]
>>> print list
[‘a’, ‘x’, ‘y’, ‘d’, ‘e’, ‘f’]
เราสามารถลบ elements ออกจาก list ด้วยการกำหนดค่าว่างเปล่าให้กับมัน:
>>> list = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
>>> list[1:3] = []
>>> print list
[‘a’, ‘d’, ‘e’, ‘f’]
และเราสามารถเพิ่ม elements เข้าใน list ด้วยการบีบมันเข้าไปใน slice ที่ว่างเปล่าเข้าไปยังตำแหน่งที่ต้องการ:
>>> list = [‘a’, ‘d’, ‘f’]
>>> list[1:1] = [‘b’, ‘c’]
>>> print list
[‘a’, ‘b’, ‘c’, ‘d’, ‘f’]
>>> list[4:4] = [‘e’]
>>> print list
[‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
8.9 List deletion
[แก้ไข | แก้ไขต้นฉบับ]การใช้ slice เพื่อลบ list elements ทำได้ไม่สะดวกนัก และมีแนวโน้มที่จะ error Python ให้ทางเลือกที่ง่ายต่อการอ่านมาก
del ลบ element ออกจาก list:
>>> a = [‘one’, ‘two’, ‘three’]
>>> del a[1]
>>> a
[‘one’, ‘three’]
อย่างที่คุณคาดไว้, del กระทำการปฏิเสธ indices และทำให้เกิด runtime error ถ้า index อยู่นอกขอบเขต
คุณสามารถใช้ slice แทน index สำหรับ del:
>>> list = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
>>> del list [1:5]
>>> print list
[‘a’, ‘f’]
โดยปรกติ slices เลือกเอา elements ทั้งหมด แต่ไม่รวม index ตัวที่สอง
8.10 Objects and values
[แก้ไข | แก้ไขต้นฉบับ]ถ้าเราดำเนินการ statements การกำหนดค่าให้กับตัวแปนเหล่านี้
a = “banana”
b = “banana”
เรารู้ว่า a และ b จะอ้างถึง string ด้วยตัวอักษร “banana” แต่เราไม่สามารถบอกได้ว่ามันจะชี้ string ตัวเดียวกันหรือไม่
สามารถเกิดขึ้นได้ทั้ง 2 สถานการณ์:
ในกรณีแรก a และ b อ้างถึงทั้งสองสิ่งที่ต่างกันซึ่งมี่คาเดียวกัน ในกรณีที่สอง a และ b อ้างถึงสิ่งเดียวกัน สิ่งที่ถูกอ้างถึงนี้เรียกว่า objects, Object คือ สิ่งที่ตัวแปรสามารถอ้างถึง
ทุกๆ object มีตัวชี้ลักษณะเฉพาะ อันซึ่งเราสามารถด้วย id function โดยแสดงตัวชี้รายละเอียดของ a และ b เราสามารถบอกได้ว่าพวกมันอ้างถึง object ตัวเดียวกันหรือไม่
>>> id (a)
135044008
>>> id (b)
135044008
โดยแท้จริงแล้ว เราจะได้รับตัวชี้รายละเอียดเป็นตัวเดียวกันทั้งสอง ซึ่งหมายถึง Python สามารถสร้าง string ตัวเดียว และ a และ bทั้งคู่อ้างถึงมัน
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id (a)
135045528
>>> id (b)
135041704
ดังนั้นลักษณะ diagram จะดูเหมือนดังนี้:
a และ b มีค่าเดียวกันแต่ไม่ได้อ้างถึง object ตัวเดียวกัน
8.11 Aliasing
[แก้ไข | แก้ไขต้นฉบับ]เมื่อตัวแปรอ้างถึง objects, ถ้าเรากำหนดตัวแปรหนึ่งให้กับอีกตัวหนึ่ง, ตัวแปรทั้งสองตัวนั้นจะอ้างถึง object ตัวเดียวกัน:
>>> a = [1, 2, 3]
>>> b = a
ในกรณีนี้ diagram จะเหมือนดังนี้:
เนื่องจาก list อันเดียวกันมีชื่อที่ต่างกันสองชื่อ a และ b เรากล่าวได้ว่ามันคือ aliased(ตัวแปรหลากหลายที่อ้างถึง object ตัวเดียวกัน)
การเปลี่ยนแปลง alias จะส่งผลถึงอีกตัวหนึ่ง:
>>> b[0] = 5
>>> print a
[5, 2, 3]
แม้ว่าการกระทำในลักษณะนี้จะมีประโยชน์ ในบางครั้งมันก้ไม่เป็นไปตามที่คาดหวังหรือไม่พึงปราถนา โดยทั่วไป มันจะปลอดภัยกว่าที่จะหลีกเลี่ยงการใช้ alias เมื่อคุณกำลังทำงานกับ object ที่เปลี่ยนแปลงง่าย อย่างนอน สำหรับ object ที่เปลี่ยนแปลงง่ายเหล่านี้ย่อมไม่มีปัญหา นั่นคือสาเหตุที่ว่าทำไม Python จึงเป็นอิสระต่อ alias strings เมื่อมันเป็นโอกาสที่จะทำให้ประหยัด
8.12 Cloning lists
[แก้ไข | แก้ไขต้นฉบับ]ถ้าเราต้องการแก้ไข list และยังคงเก็บ copy จากต้นฉบับ เราจำเป็นต้องการความสามารถในการ copy ของ list มันเอง ไม่ใช่แค่การอ้างอิง. กระบวนการนี้บางครั้งเรียกว่า cloning เพื่อหลีกเลี่ยงความคลุมเคลือของคำว่า “copy”.
วิธีที่ง่ายที่สุดในการ clone list นั้นคือการใช้ slice operator:
>>> a = [1, 2, 3]
>>> b = a[:]
>>> print b
[1, 2, 3]
การนำ slice ใดๆของ list ใหม่สร้างขึ้น ในกรณีนี้ slice ที่เราได้สร้างขึ้นประกอบไปด้วยทั้งหมดของ list ที่เรา clone มา ตอนนี้เรามีอิสระในการเปลี่ยนแปลง b โดยไม่ต้องไปกังวลกับ a:
>>> b[0] = 5
>>> print a
[1, 2, 3]
8.13 List parameters
[แก้ไข | แก้ไขต้นฉบับ]ผ่าน list เป็นอย่าง argument ปรกติผ่านตัวอ้างอิงไปยัง list ไม่ใช่การ copy ของ list. ตัวอย่าง function head เอา list เป็น parameter และ return element ตัวแรก:
def head(list):
return list[0]
นี่คือวิธีการใช้งาน:
>>> numbers = [1, 2, 3]
>>> head(numbers)
1
Parameter list และ ตัวแปร numbers เป็น alias สำหรับ object เดียวกัน
Diagram จะเหมือยเช่นนี้:
เมื่อ list object ถูกใช้ร่วมโดยสองเฟรม เราจึงลากมาอยู่ระหว่างเฟรมทั้งสอง
ถ้า function แก้ไข list parameter ตัวเรียกเห็นการเปลี่ยนแปลง ตัวอย่าง deleteHead ลบ element ตัวแรกออกจาก list:
def deleteHead(list):
def list[0]
นี่คือวิธีการใช้งานของ deleteHead:
>>> numbers = [1, 2, 3]
>>> deleteHead(numbers)
>>> print numbers
[2, 3]
ถ้า function returns list มัน returns อ้างอิงไปยัง list ตัวอย่าง tail returns list ที่ประกอบด้วยทั้งหมด แต่ element ตัวแรกของ list ที่ได้ให้ไว้:
def tail(list):
return list[1:]
นี่คือวิธีการใช้งานของ tail:
>>> numbers = [1, 2, 3]
>>> rest = tail(numbers)
>>> print rest
[2, 3]
เนื่องจาก return ค่า ได้ถูกสร้างขึ้นด้วย slice operator มันเป็น list ใหม่. การสร้าง rest และ subsequence ใดๆเปลี่ยนไปเป็น rest จะไม่มีผลกับ numbers
8.14 Nested lists
[แก้ไข | แก้ไขต้นฉบับ]Nested list เป็น list ที่ปรากฏเป็น element ในอีกlist หนึ่ง ใน list นี้ element ตัวลำดับที่สามเป็น nested list:
>>> list = [“hello”, 2.0, 5, [10, 20]]
ถ้าเรา print list[3], เราจะได้ [10, 20] เพื่อที่จะดึง element ออกมาจาก nested list เราสามารถทำได้ในสองขั้นตอน:
>>> elt = list[3]
>>> elt[0]
10
หรือเราสามารถผสมมัน:
>>> list [3][1]
20
เครื่องหมายวงเล็บประเมินผลจากซ้ายไปขวา ดังนั้น expression นี้ ได้ element ลำดับที่สามของ list และดึงเอา element ลำดับที่หนึ่งจากมันออกมา
8.15 Matrixes
[แก้ไข | แก้ไขต้นฉบับ]Nested list บ่อยครั้งทำหน้าที่แทน matrices.ตัวอย่าง the matrix:
อาจจะถูกแทนด้วยเช่นนี้:
>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
matrix เป็น list ด้วย สาม elements ที่แต่ละ element เป็นแถวของmatrix เราสามารถเลือกแถวทั้งหมดจาก matrix ด้วยวิธีปรกติ:
>>> matrix[1]
[4, 5, 6]
หรือเราสามารถตัดเอา element เพียงตัวเดียวจาก matrix โดยดารใช้รูปแบบ double-index:
>>> matrix[1][1]
5
index ตัวแรกเลือกแถว ตัวที่สองเลือกแถวในแนวตั้ง
8.16 String and lists
[แก้ไข | แก้ไขต้นฉบับ]สอง functions ที่มีประโยชน์ใน string module เกี่ยวข้องกับ lists ของ strings Split function แยก string ไปเป็น list ของ คำ โดยอัตโนมัติ ตัวเลขใดๆของ ตัวอักษร whitespace ถูกพิจารณาขอบเขตของคำ:
>>> import string
>>> song = “The rain in Spain…”
>>> string.split(song)
[‘The’, ‘rain’, ‘in’, ‘Spain…’]
optional argument เรียกว่า delimiter สามารถใช้ระบุ character เพื่อใช้เป็นขอบเขตของคำ ตัวอย่างต่อไปนี้ใช้ string ai เป็น delimiter:
>>> string.split(song, ‘ai’)
[‘The r’, ‘n in Sp’, ‘n…’,]
ข้อสังเกต delimiter จำไม่ปรากฏใน list
Join function คือครงกันข้ามกันกับ split มันเอา list ของ string และเชื่อมต่อ elements ด้วย space ระหว่างแต่ละคู่:
>>> list = [‘The’, ‘rain’, ‘in’, ‘Spain…’]
>>> string.join(list)
‘The rain in Spain…’
เหมือน split, join เอา optional delimiter ใส่เข้าระหว่าง elements:
>>> string.join(list, ‘_’)
‘The_rain_in_Spain…’
8.17 Glossary
[แก้ไข | แก้ไขต้นฉบับ]list: A named collection of objects, where each object is identified by an index.
index: An integer variable or value that indicates an element of a list.
element: One of the values in a list (or other sequence). The bracket operator selects elements of a list.
sequence: Any of the data types that consist of an ordered set of elements, with each element identified by an index.
nested list: A list that is an element of another list.
list traversal: The sequential accessing of each element in a list.
object: A thing to which a variable can refer.
aliases: Multiple variables that contain references to the same object.
clone: To create a new object that has the same value as an existing object. Copying a reference to an object creates an alias but doesn't clone the object.
delimiter: A character or string used to indicate where a string should be split.