วิธีคิดแบบนักวิทยาการคอมพิวเตอร์/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.