บทที่ 3 โครงสร้างข้อมูล (Data Structure) I#
โครงสร้างข้อมูล (data structure) เป็นกลไกที่ใช้สำหรับการจัดเก็บข้อมูลในรูปแบบที่มีโครงสร้าง เพื่อให้สามารถจัดเก็บ ค้นหา และจัดการข้อมูลได้อย่างมีประสิทธิภาพ การเข้าใจโครงสร้างข้อมูลเป็นสิ่งสำคัญอย่างยิ่งสำหรับโปรแกรมเมอร์ โดยเฉพาะอย่างยิ่งผู้ที่สนใจทางด้านวิทยาการข้อมูล (data science) เนื่องจากต้องมีการจัดเก็บ เคลื่อนย้าย และประมวลผลข้อมูลอยู่เป็นประจำ
จุดมุ่งหมายของบทนี้
เลือกใช้โครงสร้างข้อมูลประเภทลิสต์ (list) ดิกชันนารี (dictionary) ทูเปิล (tuple) เคาน์เตอร์ (counter) และเซต (set) ให้เข้ากับโจทย์ได้อย่างถูกต้อง
การใช้
for
และwhile
ร่วมกับโครงสร้างข้อมูลที่ซับซ้อนขึ้นใช้เมท็อดของโครงสร้างข้อมูลเพื่อแก้โจทย์ได้อย่างมีประสิทธิภาพ
โครงสร้างข้อมูลมีอยู่หลายประเภท ซึ่งในบทนี้เราจะศึกษาและฝึกปฏิบัติการใช้โครงสร้างข้อมูลประเภทลิสต์ (list) ดิกชันนารี (dictionary) ทูเปิล (tuple) เคาน์เตอร์ (counter) และเซต (set) ในการเก็บข้อมูล การเลือกใช้โครงสร้างข้อมูลต้องพิจารณาถึง 3 ปัจจัยหลัก
ความถูกต้องของข้อมูล: ข้อมูลจะต้องไม่สูญหายหรือบิดเบือนไปจากเจตนาของผู้ใช้งาน เช่น โครงสร้างข้อมูลบางประเภทไม่เก็บข้อมูลที่ซ้ำ หรือไม่เรียงลำดับข้อมูลที่เก็บไว้
ความรวดเร็วในการประมวลผล: โครงสร้างข้อมูลแต่ละประเภทมีวิธีการจัดเก็บข้อมูลที่แตกต่างกัน ทำให้เวลาที่ใช้ในการค้นหาและดึงข้อมูลมาใช้งานจึงต่างกันออกไป
ความสะดวกในการใช้งาน: โครงสร้างข้อมูลแต่ละประเภทมีเมท็อดหรือคำสั่งที่แตกต่างกัน ทำให้งานบางประเภทสามารถทำได้สะดวกกว่า เช่น ลิสต์มีเมท็อดที่สามารถดึงข้อมูลตามลำดับได้ง่าย หากเราต้องการดึงข้อมูลตามลำดับเช่นนี้ ควรเลือกใช้ลิสต์ในการเก็บข้อมูล
ในบทนี้และบทถัดไป เราจะศึกษาวิธีการใช้งานโครงสร้างข้อมูลในแง่มุมต่าง ๆ ดังนี้
วิธีการสร้างโครงสร้างข้อมูล
วิธีการเพิ่มข้อมูลเข้าไปในโครงสร้าง
วิธีการแก้ไขข้อมูลที่อยู่ในโครงสร้าง
วิธีการดึงข้อมูลออกมาโดยการใช้วงวน
วิธีการใช้เมท็อดต่าง ๆ ของโครงสร้างข้อมูล
การพิจารณาข้อดีข้อเสียของโครงสร้างข้อมูลแต่ละประเภท
ลิสต์#
ลิสต์ (list) เป็นโครงสร้างข้อมูลที่ใช้ในการจัดเก็บข้อมูลเป็นลำดับ ซึ่งข้อมูลภายในลิสต์จะถูกเรียงตามลำดับตามกำหนด ลิสต์มีคุณสมบัติที่สามารถเก็บข้อมูลได้หลายประเภทในคราวเดียวกัน ไม่ว่าจะเป็นจำนวนเต็ม จำนวนทศนิยม หรือสตริง
ลิสต์มีความคล้ายคลึงกับสตริงอย่างมาก ในความเป็นจริงสายอักขระก็ถือเป็นลิสต์ชนิดหนึ่งที่เก็บตัวอักขระเท่านั้น เพียงแต่สายอักขระมีเมท็อดบางอย่างที่แตกต่างจากลิสต์ ดังนั้นการทำความเข้าใจวิธีการทำงานของสายอักขระจะช่วยให้เข้าใจการทำงานของลิสต์ได้ดีขึ้น
การสร้างลิสต์ด้วย []
#
ลิสต์สามารถสร้างได้โดยใช้เครื่องหมาย []
ในการคร่อมข้อมูล โดยไม่สามารถใช้ ()
หรือ {}
แทนได้
my_first_list = []
ในตัวอย่างนี้ตัวแปร my_first_list
เป็นลิสต์เปล่าที่ไม่มีข้อมูลหรือสมาชิกใด ๆ
หากต้องการสร้างลิสต์ที่เป็นค่าคงที่ (literal) กล่าวคือสมาชิกของลิสต์ถูกระบุเอาไว้โดยตรงในโค้ด เราสามารถใช้ []
คร่อมข้อมูลที่ต้องการเก็บ (เรียกว่า สมาชิกของลิสต์) โดยที่ข้อมูลแต่ละตัวจะเป็น int float
หรือสตริงก็ได้คั่นด้วยเครื่องหมาย ,
สมมติว่าเราต้องการสร้างลิสต์ที่เก็บยอดขายหกเดือนแรก และสร้างอีกลิสต์เพื่อเก็บชื่อเดือน
sales_list = [12, 10, 5, 2, 5 10]
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'June']
ตัวแปร sales_list
และ months
เป็นลิสต์เก็บ int
และสตริงตามลำดับ ซึ่งทั้งสองลิสต์มีสมาชิกทั้งหมด 6 ตัวเท่ากัน
นอกจากนี้ ลิสต์ยังสามารถเก็บข้อมูลต่างประเภทได้ด้วย แต่การใช้งานในลักษณะนี้อาจทำให้เกิดความสับสน เช่น
sales_list = ['Jan', 12, 'Feb', 10]
โปรแกรมเมอร์มักไม่แนะนำให้ใช้ลิสต์ในลักษณะนี้ เนื่องจากอาจทำให้ยากต่อการทำความเข้าใจว่าข้อมูลแต่ละตัวในลิสต์มีความหมายอย่างไร ดังนั้นจึงควรให้ข้อมูลภายในลิสต์เป็นประเภทเดียวกันเพื่อความชัดเจน
ชื่อตัวแปรที่เก็บลิสต์#
ชื่อตัวแปรที่ใช้ในการเก็บลิสต์โดยกฎแล้วจะเป็นอะไรก็ได้ แต่เพื่อทำให้โค้ดเข้าใจได้ง่ายขึ้น โปรแกรมเมอร์มักตั้งชื่อลิสต์ตามสิ่งที่เก็บอยู่ตามด้วย _list
หรือเปลี่ยนให้เป็นพหูพจน์แทน เช่น
ถ้าลิสต์เก็บนามสกุลก็ควรจะตั้งชื่อตัวแปรว่า
last_name_list
หรือlast_names
ถ้าลิสต์เก็บจำนวนคำที่อยู่ในแต่ละประโยค ควรจะตั้งชื่อตัวแปรว่า
num_words_list
หรือnum_words
แต่ว่าจากชื่อnum_words
อาจจะกำกวมว่าเก็บไว้เป็นint
ตัวเดียวเดี่ยว ๆ หรือไม่
การสร้างลิสต์จากสตริง#
sentence = "Let's go crazy crazy crazy 'til we see the sun"
word_list = sentence.split(' ')
สตริงเมท็อด.split
ใช้เวลาเราต้องการเปลี่ยนสตริงให้เป็นลิสต์ โดยที่ต้องกำหนดว่าจะใช้สตริงอะไรแบ่งสมาชิกแต่ละตัว ในตัวอย่างนี้เราใช้ ' '
ช่องว่างในการแบ่ง ในการประมวลผลภาษาธรรมชาติเราใช้คำสั่งนี้บ่อยมากในการตัดคำ ซึ่งก็คือการเปลี่ยนสตริงให้เป็นลิสต์ของคำ
การหาความยาวของลิสต์ (จำนวนสมาชิก)#
ไพทอนมีฟังก์ชันบิวท์อิน len
ที่ใช้หาจำนวนสมาชิกของลิสต์ ซึ่งสามารถใช้ได้กับโครงสร้างข้อมูลอื่น ๆ ของไพทอนทั้งหมดอีกด้วย เช่น
sentence = "Let's go crazy crazy crazy 'til we see the sun"
word_list = sentence.split(' ')
len(word_list) #---> 10
ฟังก์ชันนี้จะคืนค่า int
เสมอ ตัวอย่างที่ใช้บ่อย ๆ คือใช้ในการสร้างลิสต์จากสตริงเพื่อนับจำนวนคำที่อยู่ในประโยคหรือข้อความ เนื่องจากภาษาที่ใช้ตัวเขียนเป็นตัวลาตินสามารถตัดคำโดยใช้คำสั่ง split
ได้ง่าย ๆ ถึงแม้ว่าจะไม่ได้แม่นยำเสมอไป
เข้าถึงสมาชิกในลิสต์โดยใช้ดัชนี#
การเข้าถึงสมาชิกแต่ละตัว เราจะใช้ตัวดำเนินการ []
คร่อมดัชนี และกฎการใช้ดัชนีเหมือนกับสตริงทุกประการ สมาชิกตัวแรกอยู่ที่ดัชนี 0 และสามารถใช้ดัชนีติดลบ ในการนับดัชนีถอยหลังจากท้ายลิสต์ได้ โดยดัชนี -1 หมายถึงสมาชิกตัวสุดท้าย, ดัชนี -2 หมายถึงสมาชิกถัดจากตัวสุดท้ายเป็นต้น
ตัวอย่างเช่น หากเรามีลิสต์ดังนี้
words = ["Let's", 'go', 'crazy', 'crazy', 'crazy', "'til", 'we', 'see', 'the', 'sun']
เราสามารถเข้าถึงสมาชิกในลิสต์ได้โดยใช้ดัชนี เช่น
คำสั่ง |
ผลลัพธ์ |
---|---|
|
|
|
|
|
|
|
|
ในกรณีที่พยายามเข้าถึงดัชนีที่ไม่อยู่ในช่วงของลิสต์ เช่น
words[20]
จะทำให้เกิดข้อผิดพลาดที่เรียกว่า IndexError
เนื่องจากไม่มีสมาชิกอยู่ที่ดัชนี 20 วิธีที่ดีที่สุดในการหลีกเลี่ยงข้อผิดพลาดนี้คือการตรวจสอบขอบเขตของลิสต์ก่อนเรียกใช้ดัชนี
การหั่นลิสต์#
การหั่นลิสต์ (list slicing) เป็นการดึงข้อมูลบางส่วนจากลิสต์ โดยใช้เครื่องหมาย []
พร้อมระบุช่วงของดัชนีที่ต้องการ การหั่นลิสต์สามารถทำได้ในลักษณะเดียวกับการหั่นสตริง โดยใช้รูปแบบ list[start:end]
ซึ่ง start
คือดัชนีเริ่มต้น และ end
คือดัชนีสุดท้าย (ไม่รวมค่าที่ดัชนี end
)
ตัวอย่างการใช้งานการหั่นลิสต์
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
คำสั่ง |
ผลลัพธ์ |
คำอธิบาย |
---|---|---|
|
|
ดัชนี 2 ถึง 4 ไม่รวม 5 |
|
|
ดัชนีเริ่มต้นถึง 3 ไม่รวม 4 |
|
|
ดัชนี 5 ถึงสุดท้าย |
การหั่นลิสต์เป็นฟังก์ชันที่มีประโยชน์อย่างมากในการจัดการข้อมูล เราสามารถใช้มันในการดึงข้อมูลย่อย ๆ ที่ต้องการได้โดยง่าย
การวนซ้ำบนลิสต์ด้วยคำสั่ง for
#
เราสามารถวนซ้ำ (iterate) บนลิสต์ได้ในลักษณะเดียวกับการวนซ้ำบนสตริง โดยสามารถวนซ้ำผ่านสมาชิกของลิสต์โดยตรง หรือวนซ้ำผ่านดัชนีของลิสต์ได้
ตัวอย่างเช่น หากเราต้องการนับจำนวนคำที่สะกดด้วยตัวพิมพ์เล็กทั้งหมดในลิสต์
word_list = ['Rick', 'and', 'Michonne', 'protect', 'Carl']
count = 0
for i in range(len(word_list)):
word = word_list[i] # ดึงค่าคำจากดัชนี i
if word.islower(): # ตรวจสอบว่าคำเป็นตัวพิมพ์เล็กทั้งหมดหรือไม่
count += 1
เราจะใช้ i
เป็นตัวดัชนีในการเข้าถึงสมาชิกแต่ละตัวในลิสต์ โดยดัชนีจะเริ่มต้นที่ 0 และเพิ่มขึ้นเรื่อย ๆ จนถึง len(word_list) - 1
อย่างไรก็ตาม การวนซ้ำแบบนี้ต้องมีการเรียกฟังก์ชัน len(word_list)
และต้องเข้าถึงสมาชิกของลิสต์ดัชนีแยกออกมาอีกคำสั่ง word_list[i]
ซึ่งอาจทำให้โค้ดยาวและซับซ้อนเกินไป
ภาษาไพทอนมีรูปแบบการวนซ้ำที่สามารถทำให้โค้ดกระชับและอ่านง่ายขึ้นโดยไม่ต้องใช้ดัชนี เช่น
word_list = ['Rick', 'and', 'Michonne', 'protect', 'Carl']
count = 0
for word in word_list:
if word.is_lower(): # ตรวจสอบว่าสะกดด้วยตัวเล็กหรือไม่
count += 1
โค้ดข้างบนนี้ได้ผลออกมาเหมือนกันทุกประการ เราวนซ้ำโดยตรงบนสมาชิกแต่ละตัวในลิสต์ ซึ่งทำให้โค้ดอ่านง่ายขึ้นและลดความซับซ้อนของการเข้าถึงสมาชิกแต่ละตัว ในการวนรอบแรก word
จะมีค่าเป็น word_list[0]
ในการวนรอบที่สอง word
จะมีค่าเป็น word_list[1]
และเลื่อนไปเรื่อย ๆ จนวนผ่านสมาชิกครบทุกตัวในลิสต์ ตัวอย่างนี้ทำให้เห็นได้ว่าเราประหยัดโค้ดได้ค่อนข้างมาก โค้ดดูสะอาดตา และสะดวกสบายในการเขียนมากกว่าการวนซ้ำบนดัชนี
อย่างไรก็ตาม ในบางกรณีเราอาจต้องการทราบดัชนีของสมาชิกที่เรากำลังประมวลผลอยู่ด้วย ซึ่งในกรณีนี้เราสามารถใช้ฟังก์ชันบิวท์อิน enumerate()
ที่ช่วยให้เราทราบทั้งดัชนีและค่าของสมาชิกในลิสต์พร้อมกัน เช่น
word_list = ['Rick', 'and', 'Michonne', 'protect', 'Carl']
count = 0
for word_index, word in enumerate(word_list):
if word.is_lower(): # ตรวจสอบว่าสะกดด้วยตัวเล็กหรือไม่
count += 1
ฟังก์ชัน enumerate()
จะคืนค่าทั้งดัชนีและสมาชิกในลิสต์ โดยในการวนรอบแรก word_index
จะมีค่าเป็น 0 และ word
จะมีค่าเป็น 'Rick'
ในการวนรอบถัดไป word_index
จะมีค่าเป็น 1 และ word
จะมีค่าเป็น 'and'
และต่อไปเรื่อยๆ จนครบทุกสมาชิกในลิสต์
การใช้ enumerate()
มีประโยชน์มากเมื่อต้องการทำงานกับข้อมูลในลิสต์ที่ต้องอ้างอิงทั้งดัชนีและสมาชิกในลิสต์พร้อมกัน เช่น การประมวลผลข้อมูลที่ต้องพิจารณาสมาชิกก่อนหน้าและถัดไปในลิสต์
ตัวดำเนินการของลิสต์ และฟังก์ชันแบบบิวท์อิน#
ลิสต์ใช้ตัวดำเนินการ และฟังก์ชันแบบบิวท์อิน หลายรูปแบบ ซึ่งคล้ายคลึงกับการทำงานของสตริง
Operator |
ความหมาย |
ตัวอย่าง |
---|---|---|
+ |
ต่อลิสต์ (concatenate) |
|
* |
ซ้ำลิสต์ |
|
|
ตรวจสอบว่าข้อมูลชิ้นนี้อยู่ในลิสต์หรือไม่ |
|
|
||
|
นิเสธของ |
|
== |
เท่ากันพอดีหรือไม่ |
|
|
||
|
คืนค่าความยาวลิสต์ |
|
การเขียนทับสมาชิกในลิสต์ด้วย []
#
เราสามารถเขียนทับ (update) สมาชิกในลิสต์โดยใช้ดัชนีร่วมกับตัวดำเนินการกำหนดค่า =
คล้าย ๆ กับการใช้ตัวแปร เราอาจจะคิดเสมือนว่าลิสต์เป็นการเก็บตัวแปรไว้หลาย ๆ ตัวแปร แบบเรียงลำดับกันตามที่เราต้องการ เช่น
accountant_list = ['เจ', 'เมย์', 'จอย', 'เมย์', 'เมย์', 'มิว']
accountant_list[0] = 'โจ้'
print(accountant_list)
# เอาท์พุต: ['โจ้', 'เมย์', 'จอย', 'เมย์', 'เมย์', 'มิว']
ในตัวอย่างนี้ เราได้เขียนทับสมาชิกตัวแรกของลิสต์ (ดัชนี 0) จาก 'เจ'
เป็น 'โจ้'
เรายังสามารถเขียนทับสมาชิกหลายตัวพร้อมกันได้โดยใช้ช่วงของดัชนี เช่น
accountant_list[1:3] = ['แนน', 'ไอซ์']
print(accountant_list)
# เอาท์พุต: ['โจ้', 'แนน', 'ไอซ์', 'เมย์', 'เมย์', 'มิว']
การเขียนทับสมาชิกในลิสต์จะช่วยให้สามารถเปลี่ยนแปลงข้อมูลภายในลิสต์ได้โดยตรง โดยไม่ต้องสร้างลิสต์ใหม่
เมท็อดของลิสต์#
ลิสต์ของเมท็อดของไพทอน เวอร์ชัน 3.12 มีอยู่ 11 เมท็อด แต่ว่าเมท็อดที่ใช้บ่อย ๆ ในการประมวลผลข้อมูลที่เกี่ยวข้องกับวิทยาการข้อมูล และการประมวลผลภาษาธรรมชาติ มีอยู่ 8 เมท็อด ได้แก่ .append() .extend() .sort() .index() .count() .insert() .pop() .remove()
นอกจากนั้นยังมีฟังก์ชันบิวอินที่ใช้กับลิสต์ได้ 4 ฟังก์ชัน ได้แก่ sort() sum() max() min()
ซึ่งเราจะเรียนรู้วิธีการใช้เมท็อดและฟังก์ชันเหล่านี้ในบทนี้
เพิ่มข้อมูลเข้าท้ายลิสต์: .append()
#
เมท็อด .append()
เป็นเมท็อดที่ใช้ในการเพิ่มสมาชิกใหม่เข้าไปที่ท้ายลิสต์ เมท็อดนี้จะทำการแก้ไขลิสต์โดยตรง ซึ่งหมายความว่าหลังจากเรียกใช้งานแล้ว ลิสต์เดิมจะถูกเปลี่ยนแปลงทันที
ตัวอย่างการใช้งาน .append()
sales_list = [23, 12, 96] # สร้างลิสต์
sales_list.append(100) # เติมข้อมูลเข้าไป
print(sales_list)
#เอาท์พุต คือ [23, 12, 96, 100]
ในตัวอย่างนี้ สมาชิกใหม่ 100
ถูกเพิ่มเข้าไปที่ท้ายลิสต์ sales_list
และลิสต์ถูกปรับเปลี่ยนทันทีโดยไม่มีการสร้างลิสต์ใหม่
คุณสมบัติของเมท็อด .append()
อินพุต: สมาชิกใหม่ที่ต้องการเพิ่มเข้าไปในลิสต์
เอาท์พุต:
None
(เนื่องจากเมท็อดนี้แก้ไขลิสต์โดยตรง)
เมท็อด .append()
เป็นหนึ่งในเมท็อดที่ได้ใช้งานบ่อยที่สุดในลิสต์ โดยเฉพาะในกรณีที่เราต้องการเก็บข้อมูลที่เปลี่ยนแปลงได้ เช่น การเพิ่มข้อมูลเข้าไปในลิสต์ทีละตัวในระหว่างการประมวลผลข้อมูล ตัวอย่างเช่น
numbers = [] # สร้างลิสต์เปล่า
for i in range(5):
numbers.append(i * 2) # เพิ่มค่าคูณสองของ i ลงในลิสต์
print(numbers)
# ผลลัพธ์: [0, 2, 4, 6, 8]
ในตัวอย่างนี้ เราใช้ .append()
เพื่อเพิ่มข้อมูลเข้าไปในลิสต์ numbers
ทีละตัว โดยค่าที่เพิ่มเข้าไปคือผลคูณของ i
และ 2 ลิสต์สุดท้ายจะประกอบด้วยค่าคูณสองของตัวเลขตั้งแต่ 0 ถึง 4
นำลิสต์หลาย ๆ ลิสต์มาต่อกัน: .extend()
#
เมท็อด .extend()
ใช้สำหรับการเพิ่มสมาชิกหลายตัวจากลิสต์หนึ่งเข้ากับลิสต์อีกลิสต์หนึ่ง โดยสมาชิกทั้งหมดจากลิสต์ที่เป็นอินพุตจะถูกคัดลอกและเพิ่มต่อท้ายลิสต์ปัจจุบัน
ตัวอย่างการใช้งาน
sales_first_six_months = [23, 12, 96, 100, 40, 10]
sales_last_six_months = [33, 44, 55, 66, 77, 88]
sales_first_six_months.extend(sales_last_six_months)
print(sales_first_six_months)
# เอาท์พุต: [23, 12, 96, 100, 40, 10, 33, 44, 55, 66, 77, 88]
ในตัวอย่างนี้ สมาชิกจากลิสต์ sales_last_six_months
ถูกเพิ่มต่อท้ายลิสต์ sales_first_six_months
โดยตรง
คุณสมบัติของเมท็อด .extend()
อินพุต: ลิสต์ที่ต้องการคัดลอกข้อมูลมาใส่
เอาท์พุต: None
(เนื่องจากเมท็อดนี้แก้ไขลิสต์โดยตรง)
ข้อควรสังเกตคือ เมท็อด .extend()
จะคัดลอกสมาชิกจากลิสต์ที่เป็นอินพุตมาใส่ในลิสต์ปัจจุบันโดยตรง ไม่ได้ย้ายสมาชิกจากลิสต์อินพุต นั่นหมายความว่า ลิสต์ที่เป็นอินพุตจะไม่ถูกเปลี่ยนแปลงแต่อย่างใด
เรียงลำดับสมาชิกในลิสต์: sorted(list)
และ .sort()
#
การเรียงลำดับลิสต์สามารถทำได้สองวิธี คือการใช้ฟังก์ชัน sorted()
และการใช้เมท็อด .sort()
ทั้งสองวิธีนี้ทำงานคล้ายกัน แต่มีความแตกต่างสำคัญที่ควรทราบ
ฟังก์ชัน sorted()
#
ฟังก์ชัน sorted()
จะคืนค่าลิสต์ใหม่ที่มีสมาชิกเรียงลำดับตามลำดับที่กำหนด โดยลิสต์ต้นฉบับจะไม่ถูกเปลี่ยนแปลง ตัวอย่างเช่น
sales_list = [23, 12, 96, 100]
sorted_sales_list = sorted(sales_list)
print(sorted_sales_list)
# ผลลัพธ์: [12, 23, 96, 100]
print(sales_list)
# ผลลัพธ์: [23, 12, 96, 100] (ลิสต์ต้นฉบับไม่ถูกเปลี่ยนแปลง)
เมท็อด .sort()
#
เมท็อด .sort()
จะทำการเรียงลำดับสมาชิกของลิสต์โดยตรง ซึ่งหมายความว่าลิสต์ต้นฉบับจะถูกเปลี่ยนแปลงและไม่คืนค่าลิสต์ใหม่ ตัวอย่างเช่น
accountant_list = ['เจ', 'เมย์', 'จอย', 'มิว']
accountant_list.sort()
print(accountant_list)
# ผลลัพธ์: ['จอย', 'มิว', 'เจ', 'เมย์']
ในตัวอย่างนี้ ลิสต์ accountant_list
ถูกเรียงลำดับใหม่ตามลำดับตัวอักษรโดยตรง
ข้อควรระวังเกี่ยวกับการเรียงลำดับคือ ฟังก์ชันและเมท็อดนี้จะเรียงลำดับสตริงภาษาไทยไม่ถูกต้องตามหลักพจนานุกรมไทย ฟังก์ชันเหล่านี้จะเรียงลำดับโดยเปรียบเทียบตัวอักษรแต่ละตัวตามลำดับการเขียน เพราะฉะนั้นจากตัวอย่าง 'เจ'
กับ 'เมย์'
มาทีหลัง 'จอย'
กับ 'มิว'
เพราะว่า เ
มาหลัง จ
และ ม
หาผลรวม ค่าสูงสุด ต่ำสุด ในลิสต์: sum(list)
, max(list)
และ min(list)
#
ฟังก์ชันแบบบิวท์อิน sum()
, max()
และ min()
เป็นฟังก์ชันที่ใช้ในการหาผลรวม ค่าสูงสุด และค่าต่ำสุดของสมาชิกในลิสต์ที่ประกอบด้วยข้อมูลประเภทตัวเลข
ตัวอย่างการใช้งาน
class_size_list = [40, 50, 60, 70, 80]
print(sum(class_size_list))
# เอาท์พุต: 300
print(max(class_size_list))
# เอาท์พุต: 80
print(min(class_size_list))
# เอาท์พุต: 40
ในตัวอย่างนี้ ฟังก์ชัน sum()
จะคืนค่าผลรวมของสมาชิกในลิสต์ ส่วนฟังก์ชัน max()
จะคืนค่าสมาชิกที่มีค่ามากที่สุด และฟังก์ชัน min()
จะคืนค่าสมาชิกที่มีค่าน้อยที่สุด
คุณสมบัติของฟังก์ชันเหล่านี้
อินพุต: ลิสต์ที่ประกอบด้วยตัวเลข
เอาท์พุต: ผลรวม หรือค่าสูงสุด หรือค่าต่ำสุด
ฟังก์ชันเหล่านี้ทำงานได้กับลิสต์ที่มีสมาชิกเป็นตัวเลขเท่านั้น หากสมาชิกในลิสต์เป็นข้อมูลประเภทอื่น เช่น สตริง อาจทำให้เกิดข้อผิดพลาด หรือในบางกรณี ไพทอนจะพยายามเรียงลำดับและเปรียบเทียบตัวอักษร ตัวอย่างเช่น
string_list = ['apple', 'banana', 'cherry']
print(max(string_list)) # ค่าสูงสุดตามลำดับอักษร
# เอาท์พุต: 'cherry'
อย่างไรก็ตาม ควรระมัดระวังเมื่อใช้งานกับลิสต์ที่มีสมาชิกหลายประเภท เช่น
mixed_list = [10, 'apple', 20]
print(max(mixed_list))
จะทำให้เกิดข้อผิดพลาด TypeError
เนื่องจากไม่สามารถเปรียบเทียบจำนวนเต็มกับสตริงได้
ข้อควรระวังอีกประการ คือฟังก์ชันเหล่านี้ไม่ใช่เมท็อดแต่ว่าเป็นฟังก์ชันแบบบิวท์อิน เพราะฉะนั้นลิสต์ไม่สามารถเรียกใช้ในรูปแบบ ลิสต์.sum()
ได้ หากมีการเรียกใช้งานในลักษณะนี้ จะเกิดข้อผิดพลาด AttributeError
ซึ่งเป็นข้อผิดพลาดที่เกิดขึ้นเมื่อพยายามเรียกเมท็อดที่ไม่มีอยู่ในข้อมูลประเภทนั้น ๆ
>>> class_size_list.sum()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'sum'
ข้อผิดพลาดนี้เกิดขึ้นเนื่องจากลิสต์ไม่มีเมท็อด sum()
ผู้ใช้ควรใช้ฟังก์ชันในตัว sum(class_size_list)
แทน
หาดัชนีของสมาชิก: .index()
#
เมท็อด .index()
ใช้สำหรับหาดัชนี (ตำแหน่ง) ของสมาชิกในลิสต์ โดยเมท็อดนี้จะคืนค่าดัชนีของสมาชิกตัวแรกที่พบ
ตัวอย่างการใช้งาน:
accountant_list = ['เจ', 'เมย์', 'จอย', 'มิว', 'จอย']
print(accountant_list.index('จอย'))
# เอาท์พุต: 2
ในตัวอย่างนี้ ค่าที่เมท็อด .index()
คืนกลับมาคือ 2 ซึ่งเป็นดัชนีของสมาชิก 'จอย'
ที่ปรากฏตัวแรกในลิสต์
คุณสมบัติของเมท็อด .index()
อินพุต: สมาชิกที่ต้องการทราบดัชนี(ตำแหน่งบนลิสต์)
เอาท์พุต: ดัชนี
ข้อควรระวัง
ก่อนใช้เมท็อดนี้ต้องเตือนความจำตัวเองก่อนว่าดัชนีของตำแหน่งแรกในลิสต์คือ 0 เช่น
'เจ'
ในตัวอย่างข้างต้นมีดัชนีเป็น 0 และ'เมย์'
มีดัชนีเป็น 1หากสมาชิกที่ค้นหาปรากฏมากกว่าหนึ่งครั้ง เมท็อด
.index()
จะคืนค่าดัชนีของสมาชิกตัวแรกที่พบ ซึ่งค้นหาจากซ้ายไปขวาในลิสต์หากสมาชิกที่ค้นหาไม่มีอยู่ในลิสต์ เมท็อดจะทำให้เกิดข้อผิดพลาด
ValueError
เช่น
>>> accountant_list.index('จิว')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 'จิว' is not in list
นับจำนวนของสมาชิกที่ระบุมา: .count()
#
เมท็อด .count()
ใช้สำหรับนับจำนวนครั้งที่สมาชิกที่กำหนดปรากฏอยู่ในลิสต์ เมท็อดนี้จะคืนค่าจำนวนครั้งที่พบ
ตัวอย่างการใช้งาน
accountant_list = ['เจ', 'เมย์', 'จอย', 'เมย์', 'เมย์', 'มิว']
print(accountant_list.count('เมย์'))
# เอาท์พุต: 3
ในตัวอย่างนี้ ค่าที่เมท็อด .count()
คืนกลับมาคือ 3 ซึ่งหมายความว่าสมาชิก 'เมย์'
ปรากฏอยู่ในลิสต์ทั้งหมด 3 ครั้ง
คุณสมบัติของเมท็อด .count()
อินพุต: สมาชิกที่ต้องการนับจำนวนครั้งที่ปรากฏในลิสต์
เอาท์พุต: จำนวนครั้งที่สมาชิกนั้นปรากฏในลิสต์
หากสมาชิกที่กำหนดไม่ปรากฏอยู่ในลิสต์ เมท็อด .count()
จะคืนค่าเป็น 0 โดยไม่ทำให้เกิดข้อผิดพลาด เช่น
print(accountant_list.count('จิว'))
# ผลลัพธ์: 0
ในกรณีนี้ ค่าที่ได้คือ 0 เนื่องจาก 'จิว'
ไม่ปรากฏอยู่ในลิสต์
แก้ไขลิสต์: .insert() .pop() .remove()
#
เมท็อดเหล่านี้ใช้สำหรับการแก้ไขสมาชิกในลิสต์โดยตรง ไม่ว่าจะเป็นการเพิ่มสมาชิก แทรกสมาชิก หรือนำสมาชิกออกจากลิสต์ เมท็อดเหล่านี้จะปรับเปลี่ยนลิสต์ต้นฉบับโดยไม่สร้างลิสต์ใหม่ ทำให้ดัชนีของสมาชิกในลิสต์เปลี่ยนแปลงไปทุกครั้งที่มีการเพิ่มหรือนำสมาชิกออก ดังนั้น เมื่อใช้งานร่วมกับวงวนฟอร์ ควรต้องใช้ความระมัดระวัง เพราะอาจทำให้เกิดความสับสนในการจัดการดัชนีของสมาชิก
แทรกสมาชิกเข้าลิสต์: .insert()
#
เมท็อด .insert()
ใช้สำหรับแทรกสมาชิกใหม่เข้าไปในตำแหน่งที่กำหนดภายในลิสต์ สมาชิกที่ถูกแทรกจะเลื่อนตำแหน่งสมาชิกที่มีอยู่เดิมต่อไปทางขวา
ตัวอย่างการใช้งาน
accountant_list = ['เจ', 'เมย์', 'จอย', 'มิว']
accountant_list.insert(1, 'เจน')
print(accountant_list)
# ['เจ', 'เจน', 'เมย์', 'จอย', 'มิว']
ในตัวอย่างนี้ สมาชิก 'เจน'
ถูกแทรกเข้ามาที่ดัชนี 1 และสมาชิกที่อยู่ในลิสต์จะเลื่อนไปยังตำแหน่งถัดไป
คุณสมบัติของเมท็อด .insert()
อินพุต:
ดัชนี (สามารถใช้ negative ดัชนีได้)
สมาชิกใหม่
เอาท์พุต:
None
(เนื่องจากลิสต์ถูกแก้ไขโดยตรง)
หากดัชนีที่ระบุมากกว่าความยาวของลิสต์ เมท็อดจะทำการเพิ่มสมาชิกใหม่ต่อท้ายลิสต์โดยอัตโนมัติ และไม่ทำให้เกิดข้อผิดพลาด
นำสมาชิกออกจากลิสต์: .remove()
#
เมท็อด .remove()
ใช้สำหรับลบสมาชิกตัวแรกที่มีค่าตรงกับข้อมูลที่ระบุ เมท็อดนี้จะทำการค้นหาจากซ้ายไปขวา และลบสมาชิกตัวแรกที่พบ
ตัวอย่างการใช้งาน
accountant_list = ['เจ', 'เมย์', 'จอย', 'มิว']
accountant_list.remove('จอย')
print(accountant_list)
# ['เจ', 'เมย์', 'มิว']
ในตัวอย่างนี้ สมาชิก 'จอย'
ตัวแรกที่พบในลิสต์จะถูกลบออก
คุณสมบัติของเมท็อด .remove()
อินพุต: ค่าของสมาชิกที่ต้องการลบออกจากลิสต์
ผลลัพธ์:
None
หากไม่มีสมาชิกที่ตรงกับค่าที่ระบุ เมท็อด.remove()
จะทำให้เกิดข้อผิดพลาด ValueError
เช่น
>>> accountant_list.remove('จิว')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
นำสมาชิกออกจากลิสต์: .pop()
#
เมท็อด .pop()
ใช้สำหรับนำสมาชิกออกจากลิสต์ตามดัชนีที่กำหนด และคืนค่าสมาชิกนั้นกลับมา เมท็อดนี้จะลบสมาชิกที่ตำแหน่งที่ระบุ และหากไม่มีการระบุดัชนี จะลบสมาชิกตัวสุดท้ายในลิสต์
ตัวอย่างการใช้งาน
accountant_list = ['เจ', 'เมย์', 'จอย', 'มิว']
removed_member = accountant_list.pop(2)
print(accountant_list)
# ['เจ', 'เมย์', 'มิว']
print(removed_member)
# จอย
ในตัวอย่างนี้ สมาชิกที่ดัชนี 2 ('จอย'
) ถูกนำออกจากลิสต์และคืนค่าให้ตัวแปร removed_member
คุณสมบัติของเมท็อด .pop()
อินพุต: ดัชนีที่ต้องการนำสมาชิกออก (สามารถใช้ดัชนีติดลบได้)
เอาท์พุต: สมาชิกที่ถูกลบออก
ลิสต์จะคืนค่าสมาชิกที่อยู่ที่ดัชนีที่กำหนดมาให้ จากนั้นก็จะดีดเอาสมาชิกตัวนั้นออกไป (เมท็อดนี้เลยชื่อว่า pop
ซึ่งแปลว่าดีดออก) หากดัชนีที่ระบุเกินความยาวของลิสต์ เมท็อดจะทำให้เกิดข้อผิดพลาด IndexError
เช่น
>>> accountant_list.pop(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
ในกรณีที่ไม่มีการระบุดัชนี เมท็อด .pop()
จะนำสมาชิกตัวสุดท้ายออกจากลิสต์
ดิกชันนารี (Dictionary)#
ดิกชันนารี หรือที่โปรแกรมเมอร์มักเรียกย่อว่า “ดิกต์ (dict)” เป็นโครงสร้างข้อมูลที่ใช้เก็บคู่ของคีย์ (key) และแวลู (value) โดยคีย์และแวลูสามารถเป็นข้อมูลประเภทใดก็ได้ ดิกชันนารีมีการทำงานคล้ายคลึงกับพจนานุกรมที่เราคุ้นเคย ซึ่งคีย์เปรียบเสมือนคำที่เราต้องการค้นหา และแวลูเปรียบเสมือนความหมายของคำนั้น ๆ อย่างไรก็ตาม ดิกชันนารีในภาษาไพทอนสามารถมีคีย์และแวลูเป็นข้อมูลประเภทใดก็ได้ ไม่จำกัดแค่คำศัพท์และความหมายเหมือนพจนานุกรม
อีกประการหนึ่งที่ดิกชันนารีในวิทยาการคอมพิวเตอร์มีความคล้ายคลึงกับพจนานุกรม คือ ดิกชันนารีถูกใช้เพื่อตอบคำถามว่า คีย์นี้คู่กับแวลูอะไร แต่ไม่สามารถตอบคำถามในทิศทางตรงกันข้ามได้ว่า แวลูนี้คู่กับคีย์อะไร ในการใช้งานดิกชันนารี เราสามารถค้นหาว่าคีย์ที่ได้รับมานั้นจับคู่กับแวลูใดได้อย่างรวดเร็ว แต่ไม่สามารถใช้แวลูเพื่อค้นหาคีย์ได้โดยตรง
ตัวอย่างการใช้ดิกชันนารีในการเก็บข้อมูล ได้แก่
การใช้งาน |
คีย์ |
แวลู |
---|---|---|
สมุดโทรศัพท์ |
ชื่อ |
เบอร์โทรศัพท์ |
พจนานุกรมไทย-อังกฤษ |
คำศัพท์ภาษาไทย |
ความหมายเป็นภาษาอังกฤษ |
ทะเบียนนิสิต |
รหัสประจำตัวนิสิต |
รายวิชาที่ลงทะเบียน |
ดัชนีท้ายเล่มหนังสือ |
คำสำคัญ |
เลขหน้าที่มีคำนั้นปรากฏอยู่ |
ระบบค้นหา (search engine) |
คำ |
หมายเลขของเอกสารที่มีคำนั้นอยู่ |
สถิติของคำในคลังข้อมูล |
คำ |
จำนวนครั้งที่พบเจอคำนั้นในคลังข้อมูล |
จากตัวอย่างแรกหากเราจัดเก็บสมุดโทรศัพท์ โดยให้คีย์เป็นชื่อแวลูเป็นเบอร์โทรศัพท์ เราจะไม่สามารถเปิดหาได้ว่าเบอร์ปริศนาที่ได้มานั้นเป็นเบอร์ของใคร
ดิกชันนารีถูกออกแบบมาเพื่อค้นหาแวลูจากคีย์ได้อย่างรวดเร็ว การค้นหาแวลูโดยใช้คีย์สามารถทำได้ในระยะเวลาคงที่ (constant time) โดยไม่ขึ้นกับจำนวนคู่คีย์แวลูที่เก็บอยู่ในดิกชันนารี ตัวอย่างเช่น หากเราต้องการค้นหาเบอร์โทรศัพท์ของคนหนึ่งในสมุดโทรศัพท์ที่เก็บในดิกชันนารี เราสามารถใช้คีย์ซึ่งเป็นชื่อของบุคคลนั้นเพื่อดึงแวลูที่เป็นหมายเลขโทรศัพท์ได้ทันที โดยไม่ต้องคำนึงถึงจำนวนข้อมูลที่เก็บอยู่
อย่างไรก็ตาม ดิกชันนารีไม่สามารถทำงานในทิศทางตรงกันข้ามได้ กล่าวคือ เราไม่สามารถค้นหาคีย์จากแวลูได้โดยตรง นั่นหมายความว่า เราไม่สามารถใช้หมายเลขโทรศัพท์เพื่อค้นหาชื่อเจ้าของหมายเลขได้ในดิกชันนารี หากต้องการค้นหาในทิศทางนี้เราจะต้องดึงเอาข้อมูลทั้งหมดจากดิกชันนารีและใช้วงวนฟอร์ในการตรวจสอบสมาชิกทุกตัวในดิกชันนารี ซึ่งเป็นอัลกอริทึมที่ใช้เวลาแบบเชิงเส้น (linear time) กล่าวคือระยะเวลาที่ใช้ขึ้นอยู่กับจำนวนคู่คีย์แวลูที่เก็บอยู่ในดิกชันนารี
การสร้างดิกชันนารีด้วย {}
#
ดิกชันนารีถูกสร้างได้ด้วยการใช้ {}
my_first_dict = {}
ตัวแปร my_first_dict
เป็นดิกชันนารีเปล่าที่ไม่มีข้อมูลเก็บอยู่เลย
เราสามารถใช้ {}
คร่อมข้อมูลคู่คีย์แวลูที่ต้องการเก็บได้โดยตรง โดยใช้รูปแบบดังนี้
ชื่อตัวแปร = {key1: value1, key2: value2, key3: value3, ..., keyn: valuen}
ในรูปแบบนี้ คีย์และแวลูจะถูกจับคู่กันโดยใช้เครื่องหมายโคลอน :
และแต่ละคู่คีย์แวลูจะถูกคั่นด้วยเครื่องหมายจุลภาค ,
เช่นเดียวกับการสร้างลิสต์ที่ใช้ ,
ในการคั่นสมาชิกแต่ละตัว
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
ดิกชันนารีนี้เก็บข้อมูลเกี่ยวกับชื่อและหมายเลขโทรศัพท์ในลักษณะของคู่คีย์และแวลู ดังนี้
คีย์ |
แวลู |
---|---|
‘ตังเม’ |
‘088-888-8888’ |
‘เป่าหลง’ |
‘099-999-9999’ |
‘เจนนี่’ |
‘011-111-1111’ |
ชื่อตัวแปรที่เก็บดิกชันนารี#
ชื่อตัวแปรที่ใช้เก็บดิกชันนารีควรบ่งบอกให้ชัดเจนว่าคีย์และแวลูคืออะไร และคั่นด้วย _to_
เพื่อเป็นการบ่งบอกว่าตัวแปรเก็บดิกชันนารีอยู่ เช่น
name_to_phone_number
เก็บชื่อเป็นคีย์ และเบอร์โทรศัพท์เป็นแวลูword_to_frequency
เก็บคำเป็นคีย์ และจำนวนครั้งที่พบเป็นแวลูstudent_id_to_name
เก็บรหัสนักศึกษาเป็นคีย์ และชื่อเป็นแวลู
แม้ว่าชื่อตัวแปรจะไม่มีผลต่อการทำงานของโปรแกรม แต่การตั้งชื่อตัวแปรที่สื่อความหมายชัดเจนจะช่วยให้โค้ดอ่านง่ายและเข้าใจง่ายมากยิ่งขึ้น โดยเฉพาะเมื่อใช้ดิกชันนารีซึ่งเป็นโครงสร้างข้อมูลที่อาจซับซ้อน
หาจำนวนคู่คีย์แวลูด้วยคำสั่ง len
#
คำสั่ง len
เมื่อใช้กับดิกชันนารีจะ คืนค่าจำนวนคู่ของคีย์แวลูที่อยู่ในดิกต์
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
len(name_to_phone_number) #--> 3
ในตัวอย่างนี้ ดิกชันนารี name_to_phone_number
มีคู่คีย์-แวลูทั้งหมด 3 คู่ ดังนั้น len(name_to_phone_number)
จะคืนค่า 3
เพิ่มข้อมูล (คู่ key-value) เข้าดิกชันนารี#
เมื่อเราสร้างดิกชันนารีขึ้นมาแล้วอันหนึ่ง เราสามารถเพิ่มคู่คีย์แวลูได้ด้วยคำสั่ง d[คีย์] = แวลู
โดยที่คีย์อาจเป็นได้ทั้งสตริงหรือตัวเลข แต่ไม่สามารถใช้ประเภทข้อมูลเช่นบูลีนหรือลิสต์เป็นคีย์ได้ ตัวอย่างเช่น
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
name_to_phone_number['โนโซมิ'] = '066-666-6666'
บรรทัดแรกเราสร้างดิกชันนารีที่เก็บค่าคีย์แวลู ดังนี้
คีย์ |
แวลู |
---|---|
‘ตังเม’ |
‘088-888-8888’ |
‘เป่าหลง’ |
‘099-999-9999’ |
‘เจนนี่’ |
‘011-111-1111’ |
หลังจากรันบรรทัดที่ 2 ข้อมูลในดิกชันนารีจะกลายเป็น
คีย์ |
แวลู |
---|---|
‘ตังเม’ |
‘088-888-8888’ |
‘เป่าหลง’ |
‘099-999-9999’ |
‘เจนนี่’ |
‘011-111-1111’ |
‘โนโซมิ’ |
‘066-666-6666’ |
ข้อควรระวัง คือคีย์ในดิกชันนารีต้องไม่ซ้ำกัน หากพยายามเพิ่มคู่คีย์-แวลูที่มีคีย์ซ้ำกับคีย์ที่มีอยู่แล้วในดิกชันนารี ข้อมูลเดิมจะถูกเขียนทับ เช่น
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
name_to_phone_number['โนโซมิ'] = '066-666-6666'
name_to_phone_number['ตังเม'] = '011-222-3333'
หลังจากรันโค้ดนี้แล้ว ข้อมูลในดิกชันนารีจะเปลี่ยนไปเป็นดังนี้
คีย์ |
แวลู |
---|---|
‘ตังเม’ |
‘011-222-3333’ |
‘เป่าหลง’ |
‘099-999-9999’ |
‘เจนนี่’ |
‘011-111-1111’ |
‘โนโซมิ’ |
‘066-666-6666’ |
ดิกชันนารีมีคีย์แวลู อยู่ 4 คู่ เท่าเดิม name_to_phone_number['ตังเม'] = '011-222-3333'
เปลี่ยนคู่คีย์แวลู ที่มี 'ตังเม'
เป็นคีย์ให้เป็นค่าใหม่ที่ป้อนเข้าไป ให้สังเกตด้วยว่าดิกชันนารีไม่ได้ลบคู่คีย์แวลูเก่า
และเติมคู่ใหม่เข้าไป ดิกชันนารีจะเขียนทับตำแหน่งเดิม
เข้าถึงแวลูด้วยคีย์: []
และ .get()
#
เราสามารถเข้าถึงค่าที่ตรงกับคีย์ในดิกชันนารีได้โดยระบุคีย์ที่ต้องการ ตัวอย่างเช่น หากเราต้องการทราบหมายเลขโทรศัพท์ของ ‘ตังเม’ จากดิกชันนารีที่เก็บหมายเลขโทรศัพท์ สามารถทำได้ดังนี้
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
name_to_phone_number['ตังเม'] # ---> '088-888-8888'
การเข้าถึงข้อมูลในดิกชันนารีในลักษณะนี้เรียกว่า การเปิดหาข้อมูลในดิกชันนารี (dictionary lookup) ซึ่งเป็นการดึงข้อมูลจากดิกชันนารีโดยไม่ต้องค้นหาจากแหล่งอื่น
ข้อควรระวังคือ หากค้นหาด้วยคีย์ที่ไม่มีในดิกชันนารี จะเกิดข้อผิดพลาด KeyError
>>> name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
>>> name_to_phone_number['โนโซมิ']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'โนโซมิ'
ข้อควรระวังอีกประการคือ เราไม่สามารถค้นหาด้วยแวลูในหาคีย์ที่คู่กันได้ เนื่องจากดิกชันนารีเก็บข้อมูลในลักษณะที่ทำให้ค้นหาจากคีย์ไปสู่แวลูได้เท่านั้น แต่ทำกลับกันไม่ได้ หากแวลูนั้นที่ค้นหาไม่ตรงกับคีย์ใดเลยจะเกิด KeyError
เช่นกัน
>>> name_to_phone_number['011-111-1111']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: '011-111-1111'
เพื่อป้องกันการเกิด KeyError
เราสามารถใช้เมท็อด .get()
เพื่อค้นหาคีย์ โดยสามารถระบุค่าที่จะคืนค่าได้ ในกรณีที่คีย์นั้นไม่มีอยู่ในดิกชันนารี
>>> word_to_freq = {'the': 50000, 'jump' : 200, 'Andy': 80}
>>> word_to_freq['Jack']
KeyError: 'Jack'
>>> word_to_freq.get('Jack')
None
>>> word_to_freq.get('Jack', 0)
0
บรรทัดที่สุดท้ายคือการเปิดหาคีย์ 'Jack'
ในดิกชันนารี แต่ถ้าหากไม่เจอให้ คืนค่า 0 ทำให้เราไม่ต้องเจอกับ KeyError
การวนซ้ำบนดิกชันนารี#
เราสามารถใช้ for
วนซ้ำไปบนคีย์ (iterate on keys) วนซ้ำไปบนแวลู (iterate on values) หรือวนซ้ำไปบนคู่คีย์แวลู (iterate on key-value pairs) ขึ้นอยู่กับการใช้งาน โดยเราจะใช้เมท็อด.keys()
, .values()
, .items()
ตามลำดับ ซึ่งเมท็อดเหล่านี้จะคืนค่าประเภทสิ่งที่วนซ้ำได้ (iterable) ซึ่งหมายถึงข้อมูลที่สามารถวนซ้ำได้
วนซ้ำไปบนคีย์#
เราสามารถใช้ for
ในการวนซ้ำไปบนดิกชันนารีได้โดยตรง ในการวนซ้ำแบบนี้ ระบบจะตีความว่าต้องการวนซ้ำไปบนคีย์แต่ละตัว (ไม่ใช่การวนซ้ำบนคู่คีย์แวลู)
ตัวอย่างการวนซ้ำไปบนคีย์
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
name_to_phone_number['โนโซมิ'] = '066-666-6666'
name_to_phone_number['ตังเม'] = '011-222-3333'
for name in name_to_phone_number:
print(name)
ผลลัพธ์ที่ได้คือ
ตังเม
เป่าหลง
เจนนี่
โนโซมิ
สังเกตว่า ตังเม
ถูกไล่เรียงออกมาเป็นอันดับแรก ถึงแม้ว่าจะถูกเขียนทับทีหลังก็ตาม โดยทั่วไปแล้วเราไม่ควรอาศัยให้ดิกชันนารีเรียงลำดับข้อมูลตามลำดับที่ข้อมูลถูกป้อนเข้าไป
หากต้องการให้โค้ดมีความกระจ่างขึ้นว่าเรากำลังวนซ้ำไปบนคีย์สามารถใช้เมท็อด.keys()
เช่น
for name in name_to_phone_number.keys():
print(name)
หากต้องการเก็บคีย์ทั้งหมดในลิสต์ สามารถใช้คำสั่ง list()
เพื่อแปลงสิ่งที่วนซ้ำได้ให้เป็นลิสต์ ดังตัวอย่างต่อไปนี้
name_list = list(name_to_phone_number.keys())
การแปลงคีย์เป็นลิสต์นี้สามารถนำไปใช้งานในกรณีที่ต้องการประมวลผลคีย์ทั้งหมดในลำดับที่ชัดเจน
วนซ้ำไปบน value#
ดิกชันนารีมีเมท็อด.values()
ที่ทำให้เราวนซ้ำไปบนแวลูได้
name_to_phone_number = {'ตังเม': '088-888-8888', 'เป่าหลง' : '099-999-9999', 'เจนนี่': '011-111-1111'}
name_to_phone_number['โนโซมิ'] = '066-666-6666'
for number in name_to_phone_number.values():
print(number)
ผลลัพธ์ที่ได้คือ
088-888-8888
099-999-9999
011-111-1111
066-666-6666
ลำดับที่ปรากฎเหมือนกันกับการวนซ้ำไปบนคีย์
เมท็อด.values()
ให้ค่าเป็นสิ่งที่วนซ้ำได้ เช่นกัน เพราะฉะนั้นเราสามารถเก็บเอาแวลูทั้งหมดใส่ลิสต์โดยการแปลงประเภทข้อมูลให้เป็นลิสต์ด้วยคำสั่ง list()
phone_numbers = list(name_to_phone_number.values())
วนซ้ำไปบนคู่คีย์แวลู#
เราสามารถใช้เมท็อด.items()
ในการวนซ้ำไปบนคู่คีย์แวลู ซึ่งเมท็อดนี้จะคืนค่าเป็นคู่คีย์แวลูที่เป็นสิ่งที่วนซ้ำได้ ตัวอย่างการใช้งานเมท็อดนี้ ดังต่อไปนี้
for name, number in name_to_phone_number.items():
print(name)
print(number)
ผลลัพธ์ที่ได้คือ
ตังเม
088-888-8888
เป่าหลง
099-999-9999
เจนนี่
011-111-1111
โนโซมิ
066-666-6666
ในตัวอย่างนี้ name
และ number
เป็นตัวแปรที่ใช้เก็บค่าคีย์และแวลูตามลำดับในแต่ละรอบของการวนซ้ำ เมท็อด .items()
จะคืนค่าเป็นคู่ของคีย์และแวลูในรูปของทูเปิล เราจะเรียนรู้เกี่ยวกับทูเปิลในหัวข้อถัดไป
ตรวจสอบว่ามีคีย์นั้นอยู่ในดิกชันนารีหรือไม่: in
#
เราสามารถใช้ตัวดำเนินการ in
เพื่อตรวจสอบว่าคีย์ที่ต้องการมีอยู่ในดิกชันนารีหรือไม่ ตัวอย่างเช่น
word_to_freq = {'the': 50000, 'jump' : 200, 'Andy': 80}
'Jack' in word_to_freq #---> False
การตรวจสอบว่าแวลูมีอยู่ในดิกชันนารีหรือไม่ทำได้ยากกว่า เนื่องจากดิกชันนารีไม่ได้ออกแบบมาเพื่อการตรวจสอบแวลูโดยตรง เราจำเป็นต้องวนซ้ำไปบนแวลูทั้งหมดเพื่อหาแวลูที่ตรงกัน ตัวอย่างการใช้วงวน for
เพื่อตรวจสอบว่าแวลู 200 มีอยู่ในดิกชันนารีหรือไม่
value_to_find = 200
word_to_freq = {'the': 50000, 'jump' : 200, 'Andy': 80}
def find_value(value_to_find, word_to_freq):
for freq in word_to_freq.values():
if value_to_find == freq:
return True
return False
find_value(value_to_find, word_to_freq) #---> True
อีกวิธีหนึ่งคือการแปลงแวลูทั้งหมดในดิกชันนารีให้เป็นลิสต์ แล้วใช้ตัวดำเนินการ in
ในการตรวจสอบ
value_to_find = 200
word_to_freq = {'the': 50000, 'jump' : 200, 'Andy': 80}
def find_value(value_to_find, word_to_freq):
freq_list = list(word_to_freq.values())
return value_to_find in freq_list
find_value(value_to_find, word_to_freq) #---> True
ซึ่งทั้งสองวิธีเป็นมักจะใช้เวลานานเนื่องจากเราจะต้องวนไล่ไปบนแวลูแต่ละตัว ยิ่งดิกชันนารีใหญ่แค่ไหนเวลาในการรันโปรแกรมก็จะนานตามไปด้วย ซึ่งต่างจากการตรวจสอบคีย์ซึ่งใช้เวลาในการรันโปรแกรมเป็นค่าคงตัว ไม่ขึ้นกับขนาดของดิกชันนารี ถ้าหากเราจำเป็นต้องมีการตรวจสอบว่ามีแวลูอะไรอยู่หรือไม่ เราไม่ควรใช้ดิกชันนารีในการเก็บข้อมูล
ลบคู่คีย์แวลู: .pop
#
เมท็อด .pop()
ใช้สำหรับลบคู่คีย์แวลูออกจากดิกชันนารี โดยต้องระบุคีย์ที่ต้องการลบ เมท็อดนี้จะคืนค่าแวลูที่ถูกลบออกมา หากคีย์ที่ระบุไม่มีอยู่ในดิกชันนารี จะเกิดข้อผิดพลาด KeyError
ตัวอย่างเช่น
word_to_freq = {'the': 50000, 'jump' : 200, 'Andy': 80}
word_to_freq.pop('the')
print(word_to_freq)
ผลลัพธ์ที่ได้คือ
{'jump': 200, 'Andy': 80}
ในกรณีที่คีย์ที่ระบุไม่มีอยู่ในดิกชันนารี เราสามารถระบุค่าเริ่มต้นในเมท็อด .pop()
เพื่อป้องกันข้อผิดพลาด KeyError
เช่น
word_to_freq = {'the': 50000, 'jump': 200, 'Andy': 80}
result = word_to_freq.pop('Jack', None)
print(result) # ผลลัพธ์: None
ทูเปิล (tuple)#
ทูเปิล เป็นโครงสร้างข้อมูลที่ใช้เก็บข้อมูลในลำดับที่แน่นอน ซึ่งมีลักษณะคล้ายคลึงกับลิสต์ โดยลิสต์สามารถทำหน้าที่ต่าง ๆ ได้เช่นเดียวกับทูเปิล การสร้างทูเปิลนั้นแตกต่างจากลิสต์ โดยเราจะใช้วงเล็บ ()
แทนวงเล็บเหลี่ยม []
เช่น
first_last_name = ('อรรถพล', 'ธำรงรัตนฤทธิ์')
ข้อแตกต่างสำคัญระหว่างทูเปิลและลิสต์คือ ทูเปิลเป็นโครงสร้างข้อมูลที่ไม่สามารถเปลี่ยนแปลงได้ (immutable) กล่าวคือ เมื่อสร้างทูเปิลขึ้นมาแล้ว เราไม่สามารถเปลี่ยนแปลงค่าของสมาชิกภายในทูเปิล หรือเพิ่มหรือลดจำนวนสมาชิกในทูเปิลได้ แม้ว่าลักษณะดังกล่าวอาจถูกมองว่าเป็นข้อจำกัด แต่การใช้ทูเปิลช่วยลดโอกาสในการเกิดข้อผิดพลาดในโปรแกรม เนื่องจากค่าต่าง ๆ ภายในทูเปิลจะไม่ถูกแก้ไขโดยไม่ตั้งใจ
พิกัดบนแผนที่โลก อาจจะถูกเก็บในทูเปิลโดยที่ดัชนี 0 เป็น latitude และดัชนี 1 เป็น longtitude อาจจะถูกเก็บในทูเปิล ดังนี้
('13.7563° N', '100.5018°')
ชื่อนามสกุล อาจจะถูกเก็บในทูเปิลโดยที่ดัชนี 0 เป็นชื่อดัชนี 1 เป็นนามสกุล ดังนี้
('อรรถพล', 'ธำรงรัตนฤทธิ์')
สี มักจะถูกจัดเก็บเป็นค่าแดงเขียวน้ำเงิน (RGB) โดยที่ดัชนี 0 เป็นค่าของสีแดง ดัชนี 1 เป็นค่าของสีเขียว ดัชนี 2 เป็นค่าของสีน้ำเงิน ดังนี้
(256, 256, 256)
ในกรณีเหล่านี้ การเพิ่มหรือลดสมาชิกในทูเปิลจะทำให้ข้อมูลสูญเสียความหมายและความชัดเจน เนื่องจากจำนวนสมาชิกของทูเปิลนั้นมีความหมายเฉพาะเจาะจง เช่น พิกัดควรมีเพียงสองตำแหน่งเท่านั้น หรือค่าของสีแบบ RGB ควรประกอบด้วยสามค่าเสมอ
การเข้าถึงข้อมูลในทูเปิลสามารถทำได้เช่นเดียวกับลิสต์ โดยใช้ดัชนีบวกและดัชนีลบ เช่น
first_last_name = ('อรรถพล', 'ธำรงรัตนฤทธิ์')
first_name = first_last_name[0]
last_name = first_last_name[1]
print (first_name) # อรรถพล
print (last_name) # ธำรงรัตนฤทธิ์
เพื่อความสะดวกเรามักจะกระจายค่าของทูเปิลใส่ตัวแปรหลาย ๆ ตัวพร้อม ๆ กัน เช่น
first_last_name = ('อรรถพล', 'ธำรงรัตนฤทธิ์')
first_name, last_name = first_last_name
print (first_name) # อรรถพล
print (last_name) # ธำรงรัตนฤทธิ์
แม้ว่าการกระจายค่าเช่นนี้สามารถทำกับลิสต์ได้เช่นกัน แต่ในทางปฏิบัติ การใช้กับทูเปิลจะเหมาะสมกว่า เนื่องจากเราสามารถมั่นใจได้ว่าจำนวนสมาชิกในทูเปิลจะไม่เปลี่ยนแปลงเมื่อโปรแกรมทำงาน ซึ่งแตกต่างจากลิสต์ที่สามารถเพิ่มหรือลดสมาชิกได้ ทำให้การคาดการณ์จำนวนสมาชิกในลิสต์ยากขึ้น
ทูเปิลมีเมท็อด.count
และ .index
เช่นเดียวกับลิสต์ และสามารถหั่นเป็นทูเปิลย่อยได้เหมือนกับลิสต์เช่นกัน แต่เนื่องจากทูเปิลมีโครงสร้างที่แน่นอนและข้อมูลแต่ละตำแหน่งมักมีประเภทที่แตกต่างกัน การใช้งานเมท็อดเหล่านี้จึงมักไม่เป็นที่นิยม
เคาน์เตอร์#
เคาน์เตอร์ เป็นคลาสย่อย หรือซับคลาส (subclass) ซึ่งหมายความว่าเคาน์เตอร์สามารถทำงานได้เกือบทุกอย่างที่ดิกชันนารีทำได้ แต่มีเมท็อดเพิ่มเติมที่ช่วยในการนับจำนวน คีย์ในเคาน์เตอร์สามารถเป็นข้อมูลประเภทใดก็ได้ แต่แวลูต้องเป็นตัวเลข (จำนวน) เท่านั้น จุดประสงค์หลักของเคาน์เตอร์คือการเก็บจำนวนครั้งที่พบคีย์แต่ละตัว
เคาน์เตอร์ไม่ใช่คลาสแบบบิวท์ (built-in class) ดังนั้นก่อนจะใช้จะต้อง import
เข้ามาก่อนที่จะเรียกใช้ เคาน์เตอร์เป็นคลาสที่เป็นส่วนหนึ่งของโมดูล collections
การสร้างเคาน์เตอร์ว่าง ๆ#
ใช้คำสั่ง Counter()
ในการสร้างเคาน์เตอร์ซึ่งเป็นคำสั่งที่ต้อง import
เข้ามาก่อน
from collections import Counter
word_count = Counter()
การสร้างเคาน์เตอร์จากดิกชันนารี#
หากมีดิกชันนารีที่แวลูเป็นจำนวนอยู่แล้ว เราสามารถแปลงดิกชันนารีนั้นเป็นเคาน์เตอร์ได้โดยตรง
word_count = Counter({'b':1, 'a':3, 'c':1})
การสร้างเคาน์เตอร์จากลิสต์#
การสร้างเคาน์เตอร์จากลิสต์ คือ การใช้เคาน์เตอร์นับค่าต่าง ๆ ที่เก็บอยู่ในลิสต์ และจัดเก็บให้ค่าทั้งหมดเป็นคีย์และจำนวนครั้งที่พบให้เก็บเป็นแวลู
letter_list = ['a', 'b', 'c', 'a','b', 'a']
letter_count = Counter(letter_list)
letter_count['a'] #--> 3
letter_count['b'] #--> 2
letter_count['c'] #--> 1
คีย์ที่ไม่ได้อยู่ในเคาน์เตอร์แวลูจะเป็น 0#
เมื่อเราค้นหาคีย์ที่ไม่ได้อยู่ในเคาน์เตอร์ ค่าแวลูที่ได้จะเป็น 0 เสมอ ซึ่งต่างจากดิกชันนารีที่ถ้าค้นหาคีย์ที่ไม่มี จะทำให้เกิดข้อผิดพลาด KeyError
letter_count['d'] #--> 0
คุณลักษณะนี้ทำให้เราใช้เคาน์เตอร์ได้สะดวกมากขึ้น โดยเฉพาะอย่างยิ่งในกรณีที่เราต้องการค้นหาว่าค่าอะไรปรากฏกี่ครั้ง หากค่าที่ค้นหาเป็นค่าที่ไม่ได้ปรากฏในเคานเตอร์เลย ค่าที่ได้กลับคืนมาก็จะเป็น 0 นอกจากนั้นแล้วเราสามารถเปลี่ยนแปลงค่าในเคาน์เตอร์ได้โดยไม่จำเป็นต้องตรวจสอบก่อนว่าคีย์นั้นเคยมีอยู่ในเคาน์เตอร์แล้วหรือยัง เช่น สมมติว่าเราต้องการนับแค่คำที่ไม่มีตัวเลขปะปนอยู่เลยที่จัดเก็บอยู่ในลิสต์ word_list
word_counter = Counter()
for word in word_list:
if word.isalpha():
word_counter[word] = word_counter[word] + 1
word_counter[word]
คืนค่ามาเป็น 0 หากคำนั้นไม่ได้ปรากฏในเคานเตอร์ซึ่งทำให้นิพจน์ ทางขวามือของเครื่องหมายเท่ากับเป็น 0 + 1
ซึ่งเป็นผลที่เราต้องการ
ถ้าหากเราจะใช้ดิกชันนารีแทนเคาน์เตอร์ก็สามารถทำได้ ดังนี้
word_counter = {}
for word in word_list:
if word.isalpha():
if word not in word_counter:
word_counter[word] = 0
word_counter[word] = word_counter[word] + 1
หากเราใช้ดิกชันนารีปกติ เราต้องตรวจสอบว่าคีย์อยู่ในดิกชันนารีอยู่แล้วหรือไม่ ถ้าไม่ได้อยู่ในดิกชันนารี เราต้องเพิ่มคู่คีย์แวลูใหม่โดยตั้งให้ค่าแวลูเป็น 0 เตรียมเอาไว้ก่อน เพื่อป้องกัน KeyError
หาค่าคีย์ที่คู่กับแวลูที่สูงที่สุด: .most_common()
#
เคาน์เตอร์มีเมท็อด .most_common()
ซึ่งใช้สำหรับหาคีย์ที่พบบ่อยที่สุด
letter_list = ['a', 'b', 'c', 'a','b', 'a']
letter_count = Counter(letter_list)
letter_count.most_common() #--> [('a', 3), ('b', 2), ('c', 1)]
letter_count.most_common(1) #--> [('a', 3)]
เมท็อดนี้มีพารามิเตอร์ที่สามารถระบุได้ว่าต้องการให้คืนค่าคีย์กี่อันดับแรก หากไม่ระบุค่าเริ่มต้น เมท็อดจะคืนค่าได้สูงสุด 20 อันดับแรก เมท็อดนี้จะคืนค่าลิสต์ของทูเปิล โดยแต่ละทูเปิลจะเป็นคู่ของคีย์และแวลูเรียงตามลำดับจากแวลูสูงไปต่ำ
เซต (Set)#
เซต เป็นโครงสร้างข้อมูลที่เก็บข้อมูลที่ไม่ซ้ำกัน และไม่มีลำดับ ซึ่งล้อกับเซตในคณิตศาสตร์ เซตมีความคล้ายคลึงกับลิสต์ คือ สามารถเก็บข้อมูล และเรียกใช้ข้อมูลที่เก็บเอาไว้ได้ แต่ข้อแตกต่างที่สำคัญ ได้แก่
เซตไม่เก็บลำดับของข้อมูล เพราะฉะนั้นเราไม่สามารถใช้ตัวดำเนินการ
[]
ในการเข้าถึงข้อมูลได้ ไม่สามารถใช้[]
ในการหั่นเซตได้ เนื่องจากเซตไม่มีลำดับที่แน่นอน ถึงแม้จะสามารถใช้วงวนฟอร์เพื่อเข้าถึงสมาชิกในเซตได้ แต่ลำดับการเข้าถึงสมาชิกแต่ละตัวจะไม่ตรงกับลำดับที่เราเพิ่มสมาชิกเข้าไปเซตไม่เก็บสมาชิกที่ซ้ำกัน ถ้าเราเพิ่มสมาชิกที่มีอยู่แล้วในเซต สมาชิกที่เพิ่มเข้าไปจะไม่ถูกเก็บ สมาชิกนั้นจะไม่ถูกเก็บซ้ำ และเซตจะไม่แสดงข้อผิดพลาดใด ๆ
การตรวจสอบว่าสมาชิกอยู่ในเซตทำได้รวดเร็ว เนื่องจากเซตไม่เก็บลำดับข้อมูล การตรวจสอบสมาชิกในเซตจึงทำได้เร็วกว่าการตรวจสอบในลิสต์ โดยอัลกอริทึมที่ใช้ในการตรวจสอบสมาชิกของเซตจะทำงานในเวลาคงที่ (เวลาที่ใช้ในการตรวจสอบสมาชิกภาพไม่ขึ้นอยู่กับขนาดของเซต)
การสร้างเซต และการหาขนาดของเซต#
เซตถูกสร้างขึ้นได้โดยการใช้ {}
หรือคำสั่ง set()
ถ้าต้องการสร้างเซตว่าง สามารถใช้ {}
หรือคำสั่ง set()
ได้เลย ดังตัวอย่างต่อไปนี้
basket = {}
basket = set()
หากต้องการสร้างเซตแบบเป็นค่าคงที่ (literal) กล่าวคือสมาชิกของลิสต์ถูกระบุเอาไว้โดยตรงในโค้ด
เราสามารถใช้ {}
ในการสร้างเซต และใส่สมาชิกที่ต้องการเก็บในเซตลงไปใน {}
ซึ่งสมาชิกแต่ละตัวจะต้องคั่นด้วย ,
และสมาชิกที่ซ้ำกันจะถูกเก็บเพียงตัวเดียว ดังตัวอย่างต่อไปนี้
basket = {'apple', 'orange', 'apple', 'orange', 'banana'}
basket # เก็บแค่ {'orange', 'banana', 'apple'}
หากใช้คำสั่ง set
ในการสร้างเซต จะต้องใส่ลิสต์หรือสตริงที่ต้องการเก็บในเซตลงไปใน set()
ดังตัวอย่างต่อไปนี้
basket = set(['apple', 'orange', 'apple', 'orange', 'banana'])
basket # เก็บแค่ {'orange', 'banana', 'apple'}
เพราะฉะนั้นเราสามารถใช้เซตในการเปลี่ยนสมาชิกในลิสต์ให้เหลือแต่สมาชิกที่ไม่ซ้ำกันได้ โดยการเปลี่ยนลิสต์ให้เป็นเซตด้วยคำสั่ง set
และนำผลลัพท์ที่ได้เปลี่ยนกลับให้เป็นลิสต์ด้วยคำสั่ง list
ดังตัวอย่างต่อไปนี้
fruits = ['apple', 'orange', 'apple', 'orange', 'banana']
fruit_set = set(fruits)
fruit_list_no_duplicate = list(fruit_set)
วิธีการหาขนาดของเซต (หรือจำนวนสมาชิกของเซต) คล้ายคลึงกับการหาขนาดของลิสต์ และการหาขนาดของดิกชันนารี เราใช้ len()
ในการหาขนาดของเซตได้ ดังตัวอย่างต่อไปนี้
basket = {'apple', 'orange', 'apple', 'orange', 'banana'}
len(basket) # 3
การตรวจสอบการเป็นสมาชิกโดยใช้ in
#
เราสามารถใช้ตัวดำเนินการ in
เพื่อตรวจสอบว่าข้อมูลที่ได้มาเป็นสมาชิกของเซตหรือไม่ ตัวอย่างเช่น
languages = {'French', 'English', 'German', 'Chinese'}
'English' in languages # True
'Thai' in languages # False
เซตสละความสามารถในการเก็บลำดับของข้อมูล เพื่อแลกมากับความเร็วในการหาข้อมูล การตรวจสอบการเป็นสมาชิกในลิสต์ต้องไล่ตรวจสอบสมาชิกทีละตัวโดยใช้เวลาเชิงเส้น (linear time) ซึ่งหมายความว่าเวลาที่ใช้ในการค้นหาจะเพิ่มขึ้นตามจำนวนสมาชิกในลิสต์ ในทางตรงกันข้ามเซตใช้โครงสร้างข้อมูลแฮช (hashing) ซึ่งช่วยให้การค้นหาสมาชิกสามารถทำได้ในเวลาคงที่ (constant time) โดยไม่ขึ้นกับจำนวนสมาชิกที่อยู่ในเซต ทำให้เซตเหมาะสมกว่าลิสต์สำหรับการตรวจสอบการเป็นสมาชิก โดยเฉพาะเมื่อมีจำนวนข้อมูลมาก
การวนซ้ำบนเซต#
เราสามารถใช้ for ลูปเพื่อเข้าถึงสมาชิกทุกตัวในเซตได้ เช่นเดียวกับการวนซ้ำในลิสต์ แต่เนื่องจากเซตไม่มีการเก็บลำดับของข้อมูล การวนซ้ำด้วย for จึงไม่ได้เรียงลำดับตามที่เราเพิ่มข้อมูลเข้าไป
ตัวอย่าง#
languages = {'French', 'English', 'German'}
for language in languages:
print(language)
ผลลัพธ์ที่ออกมาคือ
German
English
French
แม้ผลลัพธ์ที่ได้ดูเหมือนว่าเซตจะเก็บข้อมูลโดยเรียงตามพจนานุกรม แต่ตามนิยามของเซตแล้ว เซตไม่ได้จัดลำดับข้อมูลแต่อย่างใด ดังนั้น ลำดับการแสดงผลอาจเปลี่ยนแปลงได้ในเวอร์ชันอื่นของไพทอน เพราะการจัดลำดับไม่ใช่คุณสมบัติของเซต
การเพิ่มสมาชิกในเซตด้วย add()
#
เราสามารถเพิ่มสมาชิกในเซตได้โดยใช้คำสั่ง add
ซึ่งต่างจากคำสั่ง append
ของลิสต์ คำว่า append ภาษาอังกฤษแปลว่าเพิ่มไปตรงท้าย แต่คำว่า add แปลว่าเพิ่มเข้าไปโดยไม่ได้คำนึงถึงลำดับของสมาชิก ผู้พัฒนาภาษาไพทอนเลือกใช้คำว่า add เพื่อแสดงให้เห็นว่าเซตไม่เก็บลำดับของสมาชิก
ตัวอย่าง#
สมมติว่าเราทำโจทย์เดียวกับตัวอย่างที่ผ่านมา เราต้องการสร้างเซตของชื่อนักเรียนที่ลงท้ายด้วยสระอาจากลิสต์รายชื่อนักเรียน เราสามารถใช้คำสั่ง add
เพื่อเพิ่มสมาชิกที่ต้องการเข้าไปทีละตัว แทนที่การใช้เซตคอมพลิเฮนชันได้ดังนี้
student_names = ['อาทิตยา', 'วิภา', 'อรรถพล', 'วิภา', 'คริส', 'สุชาดา']
aa_name_set = {} # จะใช้ aa_name_set = set() แทนก็ได้
for name in student_names:
if name.endswith('า'):
aa_name_set.add(name)
เอาสมาชิกออกจากเซตด้วย remove()
และ discard()
#
แม้ว่าคำสั่งนี้อาจไม่ถูกใช้งานบ่อยนัก แต่การลบสมาชิกออกจากเซตเป็นสิ่งที่ควรรู้เพื่อความสมบูรณ์ของการใช้งานเซต เมท็อด remove()
ใช้ในการลบสมาชิกออกจากเซตโดยเราต้องระบุสมาชิกที่ต้องการลบ หากสมาชิกนั้นไม่มีอยู่ในเซต จะทำให้เกิดข้อผิดพลาด KeyError
ตัวอย่าง#
สมมติว่าเรามีเซตของตัวเลือกที่เป็นไปได้ในแบบสอบถาม เช่น Strongly disagree, Disagree, Neutral, Agree, และ Strongly agree และเราต้องการลบตัวเลือก “Strongly disagree” และ “Strongly agree” ออกจากเซต
possible_responses = {'Strongly disagree', 'Disagree', 'Neutral', 'Agree', 'Strongly agree'}
possible_responses.remove('Strongly disagree')
possible_responses.remove('Strongly agree')
หากพยายามลบสมาชิกที่ไม่มีอยู่ในเซตด้วย remove()
จะทำให้เกิดข้อผิดพลาด KeyError
ดังตัวอย่างนี้
possible_responses.remove('Maybe') # จะเกิด KeyError เพราะ 'Maybe' ไม่มีอยู่ในเซต
หากต้องการลบสมาชิกออกจากเซตโดยไม่ต้องตรวจสอบว่าสมาชิกนั้นมีอยู่หรือไม่ สามารถใช้เมท็อด discard()
แทน remove()
ซึ่งจะไม่ทำให้เกิดข้อผิดพลาด KeyError
แม้สมาชิกนั้นไม่มีอยู่ในเซต
possible_responses.discard('Maybe') # ไม่เกิดข้อผิดพลาดแม้ 'Maybe' ไม่มีอยู่ในเซต
discard()
มีประโยชน์ในกรณีที่ไม่แน่ใจว่าสมาชิกที่ต้องการลบมีอยู่ในเซตหรือไม่ ช่วยให้โปรแกรมไม่เกิดข้อผิดพลาดและทำงานต่อไปได้อย่างราบรื่น
การดำเนินการของเซต: อินเตอร์เซกชัน ยูเนียน และผลต่างของเซต#
เซตในภาษาไพทอนรองรับการดำเนินการของเซตทุกตัว สมมติว่าเรามีเซต A เก็บอยู่ในตัวแปร setA
และเซต B เก็บอยู่ในตัวแปร setB
อินเตอร์เซกชัน (A ∩ B) คือ การสร้างเซตที่ประกอบด้วยสมาชิกที่อยู่ทั้งในเซต A และเซต B ภาษาไพทอนใช้คำสั่ง
setA.intersection(setB)
ยูเนียน (A ∪ B) คือ การสร้างเซตที่ประกอบด้วยสมาชิกที่อยู่ในเซต A หรือเซต B อย่างน้อยหนึ่งเซต ภาษาไพทอนใช้คำสั่ง
setA.union(setB)
การลบกันของเซต (A - B) คือ การสร้างเซตที่ประกอบด้วยสมาชิกที่อยู่ในเซต A แต่ไม่อยู่ในเซต B ภาษาไพทอนใช้คำสั่ง
setA - setB
หรือsetA.difference(setB)
เซตในโลกของการประมวลผลภาษาธรรมชาติมักจะใช้ในการเก็บรายการคำศัพท์ (vocabulary หรือ vocab) เช่น คำศัพท์ที่ปรากฎทั้งหมดในข้อสอบชุดหนึ่ง คำศัพท์ที่เห็นทั้งหมดในคลังข้อมูล (corpus ชุดข้อมูลที่รวบรวมข้อมูลภาษาเอาไว้จำนวนมาก) คำศัพท์ที่แบบจำลองเข้าใจความหมายอยู่แล้ว เซตเหมาะแก่การเก็บรายการคำศํพท์ เพราะ รายการคำศัพท์มักประกอบด้วยคำศัพท์ที่พบเห็นอย่างน้อยหนึ่งครั้ง โดยไม่คำนึงว่าเกิดขึ้นซ้ำหรือไม่ และไม่คำนึงถึงลำดับการเกิดของคำศัพท์ นอกจากนั้นแล้วเซตในภาษาไพทอนยังรองรับการใช้การดำเนินการของเซตได้อย่างสะดวกสบายอีกด้วย
ในตัวอย่างต่อไปนี้ เรามีคำศัพท์จากแบบจำลองภาษาขนาดใหญ่ที่ครอบคลุมหลายภาษา เก็บไว้ในตัวแปร multilingual_vocab
และมีคำศัพท์จากแบบจำลองภาษาไทย เก็บไว้ในตัวแปร thai_vocab
ตัวอย่าง: อินเตอร์เซกชัน#
สมมติว่าเราต้องการหาว่าคำศัพท์ที่ปรากฎในทั้งสองเซต คือ multilingual_vocab
และ thai_vocab
สามารถใช้คำสั่ง intersection
ในการหาคำศัพท์ที่ปรากฎในทั้งสองตัวแปรได้ดังนี้
multilingual_vocab = {'hello', 'สวัสดี', '你好', 'สวัสดี', 'สวัสดี', 'สวัสดี'}
thai_vocab = {'สวัสดี', 'ขอบคุณ'}
multilingual_vocab.intersection(thai_vocab) # {'สวัสดี'}
หลังจากรันโค้ดแล้วลอง print
ค่าที่ปรากฎอยู่ในตัวแปรจะได้ผลดังนี้
print(multilingual_vocab)
print(thai_vocab)
เอาท์พุธที่ปรากฎบนหน้าจอ คือ
{'你好', 'สวัสดี', 'hello'}
{'ขอบคุณ', 'สวัสดี'}
คำสั่ง intersection
คืนค่าเป็นเซตใหม่ขึ้นมาต่างหาก แยกต่างหากจาก multilingual_vocab
และ thai_vocab
ที่เราใช้ในการเรียกคำสั่ง หลังจากเรียกคำสั่ง set operation แล้ว สมาชิกของ multilingual_vocab
และ thai_vocab
จะไม่เปลี่ยนแปลง
เพราะฉะนั้นที่ถูกต้องคือ ต้องเก็บค่าที่คืนมาจากคำสั่งไว้ในตัวแปรใหม่
multilingual_vocab = {'hello', 'สวัสดี', '你好', 'สวัสดี', 'สวัสดี', 'สวัสดี'}
thai_vocab = {'สวัสดี', 'ขอบคุณ'}
overlapping_vocab = multilingual_vocab.intersection(thai_vocab) # {'สวัสดี'}
หากเราต้องการทราบจำนวนสมาชิกของแต่ละเซต สามารถใช้ len()
ในการหาได้ ดังตัวอย่างต่อไปนี้
print(len(multilingual_vocab))
print(len(thai_vocab))
print(len(overlapping_vocab))
เอาท์พุธที่ปรากฎบนหน้าจอ คือ
4
2
1
ตัวอย่าง: ยูเนียน#
สมมติว่าเราต้องการขยายความสามารถของโมเดลหลากภาษา โดยการขยายคำศัพท์ ของโมเดลหลากภาษาให้มีคำศัพท์ที่มาจากแบบจำลองภาษาไทยด้วย สามารถใช้คำสั่ง union
ในการขยายคำศัพท์ของโมเดลหลากภาษาได้ดังนี้
multilingual_vocab = {'hello', 'สวัสดี', '你好', 'สวัสดี', 'สวัสดี', 'สวัสดี'}
thai_vocab = {'สวัสดี', 'ขอบคุณ'}
larger_vocab = multilingual_vocab.union(thai_vocab)
print(larger_vocab)
หลังจากรันโค้ดแล้วลอง print
ค่าที่ปรากฎอยู่ในตัวแปรจะได้ผลดังนี้
{'สวัสดี', 'hello', 'ขอบคุณ', '你好'}
คำสั่ง union
คืนค่าเป็นเซตใหม่ขึ้นมาต่างหาก แยกต่างหากจาก multilingual_vocab
และ thai_vocab
ที่เราใช้ในการเรียกคำสั่ง เช่นเดียวกับการใช้คำสั่ง intersection
ข้อสังเกตอีกอย่างหนึ่งคือ สมาชิกของเซตที่คืนมาจากการใช้คำสั่ง union
จะไม่เรียงลำดับตามพจนานุกรม หรือเรียงลำดับใด ๆ เลย แต่เราสามารถใช้ sorted()
ในการเรียงลำดับสมาชิกของเซตได้ ดังตัวอย่างต่อไปนี้
multilingual_vocab = {'hello', 'สวัสดี', '你好', 'สวัสดี', 'สวัสดี', 'สวัสดี'}
thai_vocab = {'สวัสดี', 'ขอบคุณ'}
larger_vocab = multilingual_vocab.union(thai_vocab)
print(sorted(larger_vocab))
เอาท์พุตที่ปรากฎบนหน้าจอ คือ
['hello', 'ขอบคุณ', 'สวัสดี', '你好']
สังเกตว่าผลที่ได้จะออกมาเป็นลิสต์ ซึ่งเป็นพฤติกรรมที่สมเหตุสมผลของคำสั่ง sorted
เนื่องจากเราจำเป็นต้องใช้โครงสร้างข้อมูลที่มีการเก็บลำดับของสมาชิกแต่ละตัว
ตัวอย่าง: ผลต่างของเซต#
สมมติเราต้องการทราบว่า thai_vocab
มีคำศัพท์ภาษาไทยคำใดบ้าง ที่ multilingual_vocab
ไม่มี สามารถใช้คำสั่ง difference
ในการหาคำศัพท์ได้ดังนี้
multilingual_vocab = {'hello', 'สวัสดี', '你好', 'สวัสดี', 'สวัสดี', 'สวัสดี'}
thai_vocab = {'สวัสดี', 'ขอบคุณ'}
thai_only_vocab = thai_vocab.difference(multilingual_vocab)
print(thai_only_vocab)
หลังจากรันโค้ดแล้วลอง print
ค่าที่ปรากฎอยู่ในตัวแปรจะได้ผลดังนี้
{'ขอบคุณ'}
คำสั่ง difference
คืนค่าเป็นเซตใหม่ขึ้นมาต่างหาก แยกต่างหากจาก multilingual_vocab
และ thai_vocab
ที่เราใช้ในการเรียกคำสั่ง เช่นเดียวกับการใช้คำสั่ง intersection
และ union
สรุปเรื่องเซต#
เซตในภาษาไพทอนเป็นโครงสร้างข้อมูลที่เหมาะสมกับการเก็บข้อมูลที่ไม่มีการจัดลำดับ และไม่มีการเก็บข้อมูลที่ซ้ำกัน โดยเซตในภาษาไพทอนมีความสามารถในการใช้ set operation ได้ทั้งหมด 3 ตัว คือ intersection union และการลบกันของเซต ในการประมวลผลภาษาธรรมชาติเซตมักถูกใช้ในการเก็บรายการคำศัพท์ หรือเรียกว่า vocabulary
คำสั่งของเซตในภาษาไพทอน สรุปเป็นตารางได้ดังนี้
operation |
สัญลักษณ์ทางคณิตศาสตร์ |
คำสั่งในไพทอน |
---|---|---|
intersection |
A ∩ B |
|
union |
A ∪ B |
|
difference |
A - B |
|
ทั้งสามคำสั่งจะคืนค่าออกมาเป็นเซตใหม่แยกต่างหากจาก setA
และ setB
ที่เราใช้ในการเรียกคำสั่ง หลังจากเรียกคำสั่ง set operation แล้ว สมาชิกของ setA
และ setB
จะไม่เปลี่ยนแปลง
คอมพริเฮนชัน (Comprehension)#
ก่อนหน้านี้เราได้เรียนวิธีการสร้างลิสต์ ดิกต์ และเซ็ตด้วยวิธีการดังนี้
my_list = list()
my_list2 = []
my_dict = dict()
my_dict2 = {}
my_set = set()
my_set = set(my_list)
ลิสต์คอมพริเฮนชัน (List comprehension)#
ลิสต์คอมพริเฮนชัน (List comprehension) คือสร้างลิสต์ขึ้นมาจากสิ่งที่เป็น iterable เช่น ลิสต์ ดิกชันนารี และเซ็ต ซึ่งเป็นกรณีการใช้ที่เกิดขึ้นบ่อย เนื่องจากมีหลายครั้งที่เราต้องแปลงจากลิสต์เป็นอีกลิสต์หนึ่งซึ่งสมาชิกข้างในถูกแปลงให้เป็นอย่างหนึ่ง
ตัวอย่าง#
สมมติว่าเรามีลิสต์ของสตริง แต่เราต้องการเปลี่ยนให้เป็นตัวใหญ่ทั้งหมด เราสามารถสร้างลิสต์ใหม่เตรียมไว้รับ output จากนั้นทำการวนลูปบนสมาชิกของลิสต์ แปลงเป็นตัวใหญ่ จากนั้นก็ .append
เข้าสู่ลิสต์ที่จะเป็น output ดังนี้
sentence = ['programming', 'is', 'very', 'interesting']
new_sentence = []
for w in sentence:
new_sentence.append(w.upper())
print(new_sentence)
#ผลลัพธ์ : ['PROGRAMMING', 'IS', 'VERY', 'INTERESTING']
เราสามารถเขียนให้กระชับได้โดยการใช้ list comprehension ดังนี้
sentence = ['programming', 'is', 'very', 'interesting']
new_sentence2 =[w.upper() for w in sentence]
print(new_sentence2)
#ผลลัพธ์ : ['PROGRAMMING', 'IS', 'VERY', 'INTERESTING']
ตัวอย่าง#
สมมติว่าเราต้องการเปลี่ยนให้จากลิสต์เดิมให้เป็นลิสต์ที่มีความยาวของสตริงแต่ละตัวแทน เราสามารถทำด้วยวิธีที่คล้ายคลึงกัน
sentence = ['programming', 'is', 'very', 'interesting']
length_list = []
for w in sentence:
length_list.append(len(w))
print (length_list)
#ผลลัพธ์ : [11, 2, 4, 11]
เราสามารถเขียนให้กระชับได้โดยการใช้ list comprehension ดังนี้
sentence = ['programming', 'is', 'very', 'interesting']
length_list = [len(w) for w in sentence]
print(length_list)
#ผลลัพธ์ : [11, 2, 4, 11]
วิธีการใช้ list comprehension มีดังนี้
[expression for ตัวแปร in iterable]
เช่น
[w.upper() for w in sentence]
[len(w) for w in sentence]
นิพจน์ (expression
) คือสูตรหรือคำสั่งที่ใช้แปลงไอเท็มแต่ละไอเท็มในลิสต์ เซต หรือดิกชันนารี ให้กลายเป็นสมาชิกของเซตที่เรากำลังสร้างขึ้น
สิ่งที่วนซ้ำได้ (iterable)
คือข้อมูลที่สามารถวนซ้ำได้ เช่น ลิสต์ เซต หรือดิกชันนารี
คอมพริเฮนชันแบบมีเงื่อนไข#
เราสามารถระบุเพิ่มเติมได้ด้วยว่าสมาชิกตัวไหนบ้างใน iterable ที่เป็น input จะถูกรวมไว้ในลิสต์ output
ตัวอย่าง#
สมมติว่าเราอยากแปลงลิสต์ที่มีคำในประโยคมาเป็นลิสต์ที่มีความยาวของแต่ละคำในประโยคอยู่ โดยที่เราสนใจเฉพาะคำที่มีความยาวมากกว่า 2 ตัวอักษร
sentence = ['programming', 'is', 'very', 'interesting']
length_list = []
for w in sentence:
if (len(w) > 2):
length_list.append(len(w))
print (length_list)
#ผลลัพธ์ : [11, 4, 11]
เราสามารถเขียนโค้ดให้กระชับขึ้นโดยใช้ list comprehension ได้ดังนี้
sentence = ['programming', 'is', 'very', 'interesting']
length_list = [len(w) for w in sentence if len(w) >2]
print(length_list)
#ผลลัพธ์ : [11, 4, 11]
ตัวอย่าง#
สมมติว่าเรามีลิสต์ของคำในประโยคอยู่ แต่ว่าเราอยากได้ลิสต์ที่มีคำที่เป็นตัวอักษรภาษาไทยเท่านั้น
import re
word_list = ['บท', 'นี้', 'เกี่ยวกับ', 'list', 'comprehension', 'และ', 'อื่นๆ']
new_word_list = []
for word in word_list:
if re.match('[ก-์]+', word):
new_word_list.append(word)
print(new_word_list)
#ผลลัพธ์ : ['บท', 'นี้', 'เกี่ยวกับ', 'และ', 'อื่นๆ']
เราสามารถเขียนโค้ดให้กระชับขึ้นโดยใช้ list comprehension ได้ดังนี้
import re
word_list = ['บท', 'นี้', 'เกี่ยวกับ', 'list', 'comprehension', 'และ', 'อื่นๆ']
new_word_list = [word for word in word_list if re.match('[ก-์]+', word)]
print(new_word_list)
#ผลลัพธ์ : ['บท', 'นี้', 'เกี่ยวกับ', 'และ', 'อื่นๆ']
สรุปการใช้คอมพริเฮนชันแบบมีเงื่อนไข#
วิธีการใช้ list comprehension แบบมีเงื่อนไข มีดังนี้
[expression for ตัวแปร in iterable if เงื่อนไข]
เช่น
[len(w) for w in sentence if len(w) >2]
[word for word in word_list if re.match('[ก-์]+', word)]
เงื่อนไข (มีหรือไม่มีก็ได้)
เป็นนิพจน์ที่แปลงสมาชิกให้เป็นค่าบูลีน ถ้าบูลีนเป็น True
สมาชิกตัวนั้นจะถูกเพิ่มเข้าไปในลิสต์ เซต หรือดิกต์ที่กำลังสร้างขึ้น แต่ถ้าบูลีนเป็น False
สมาชิกตัวนั้นจะไม่ถูกเพิ่มเข้าไปในลิสต์ เซต หรือดิกต์ที่กำลังสร้างขึ้น
เซตคอมพริเฮนชัน (Set comprihension)#
หลักการและวิธีการใช้ set comprehension แทบจะเหมือนกันกับ list comprehension เป็นการสร้างเซ็ตขึ้นมาจาก iterable อีกอันหนึ่งโดยอาจมีแปลงค่าของสมาชิกด้วยฟังก์ชันต่าง ๆ และ/หรือกรองเอาสมาชิกบางตัวออกโดยการกำหนดเงื่อนไขบูลีน
วิธีการใช้ set comprehension เหมือน list comprehension เพียงแค่เปลี่ยนเครื่องหมาย []
เป็น {}
{expression for ตัวแปร in iterable if เงื่อนไข}
ตัวอย่าง#
Vocabulary หมายถึงเซ็ตของคำศัพท์ทั้งหมดที่เราต้องการวิเคราะห์ หรือนำมาเป็นส่วนหนึ่งของโมเดล จะนับเฉพาะคำที่รูปไม่ซ้ำกัน
สมมติว่าเรามีลิสต์ของคำทั้งหมดที่มีอยู่ในคลังข้อมูล เราต้องการทราบ vocabulary ของคลังข้อมูลนี้ว่ามีคำว่าอะไรบ้าง โดยนับเฉพาะคำที่เป็นตัวภาษาอังกฤษเท่านั้น
word_list = ['baby', 'baby', 'baby', 'oh', '...', 'baby', 'baby', 'no','!']
vocab = set()
for word in word_list:
if word.isalpha():
vocab.add(word)
print(vocab)
#ผลลัพธ์ : {'baby', 'oh', 'no'}
เราสามารถเขียนโค้ดให้กระชับขึ้นโดยใช้ set comprehension ได้ดังนี้
word_list = ['baby', 'baby', 'baby', 'oh', '...', 'baby', 'baby', 'no','!']
vocab2 = {word for word in word_list if word.isalpha()}
print(vocab2)
#ผลลัพธ์ : {'baby', 'oh', 'no'}
ตัวอย่าง#
สมมติว่าเราต้องการสร้างเซตของชื่อนักเรียนที่ลงท้ายด้วยสระอาจากลิสต์รายชื่อนักเรียน
student_names = ['อาทิตยา', 'วิภา', 'อรรถพล', 'วิภา', 'คริส', 'สุชาดา']
aa_name_set = {name for name in student_names if name.endswith('า')}
เราสามารถใช้เซตคอมพริเฮนชันในการสร้างเซตของชื่อนักเรียนที่ลงท้ายด้วยสระอาได้ด้วยคำสั่งบรรทัดเดียว โครงสร้างของคำสั่งแบ่งเป็นสามส่วนดังนี้
นิพจน์ ไม่มีการเปลี่ยนแปลงชื่อนักเรียน แต่เราใช้
name
ในการเข้าถึงชื่อนักเรียนแต่ละคนสมาชิกเป็นชื่อที่ได้จากการใช้
for
ในการวนซ้ำเพื่อเข้าถึงชื่อนักเรียนทุกคนในลิสต์student_names
ซึ่งเป็นสิ่งที่วนซ้ำได้เงื่อนไขการเข้าสู่เซต เราใช้
name.endswith('า')
ในการตรวจสอบว่าชื่อนักเรียนลงท้ายด้วยสระอาหรือไม่ ถ้าลงท้ายด้วยสระอา ชื่อนักเรียนจะถูกเพิ่มเข้าไปในเซตที่กำลังสร้างขึ้น แต่ถ้าไม่ลงท้ายด้วยสระอา ชื่อนักเรียนจะไม่ถูกเพิ่มเข้าไปในเซตที่กำลังสร้างขึ้น
ดิกต์คอมพริเฮนชัน (Dict comprehension)#
หลักการใช้ dict comprehension ก็คล้ายคลึงกันกับ list comprehension และ set comprehension เพียงแต่ว่าเราต้องกำหนดว่า key และ value ของดิกต์ที่เราต้องการสร้างขึ้นจะต้องเป็นอะไรบ้าง
วิธีการใช้ dict comprehension มีดังนี้
{expression-key:expression-value for ตัวแปร in iterable if เงื่อนไข}
ตัวอย่าง#
สมมติว่าเรามีรายชื่อของนักเรียนอยู่ในลิสต์ และเราต้องการสร้างดิกต์ที่ key เป็นชื่อนักเรียน และ value เป็นหมายเลขกลุ่ม 1-3 เพื่อที่จะจัดนักเรียนออกเป็น 3 กลุ่ม
from random import randint
students = ['Panyut', 'Mild', 'Bew', 'Fluke', 'Paolong', 'Tangmay', 'Ya']
student_to_group = {}
for student in students:
student_to_group[student] = randint(1,3)
print(student_to_group)
#ผลลัพธ์ : {'Panyut': 2, 'Mild': 3, 'Bew': 1, 'Fluke': 2, 'Paolong': 2, 'Tangmay': 2, 'Ya': 1}
เราสามารถเขียนโปรแกรมข้างบนให้กระชับขึ้นโดยใช้ dict comprehension ได้
students = ['Panyut', 'Mild', 'Bew', 'Fluke', 'Paolong', 'Tangmay', 'Ya']
student_to_group = {student:randint(1,3) for student in students}
print(student_to_group)
#ผลลัพธ์ : {'Panyut': 2, 'Mild': 3, 'Bew': 1, 'Fluke': 2, 'Paolong': 2, 'Tangmay': 2, 'Ya': 1}
ตัวอย่าง#
ในการสร้างโมเดลเกี่ยวกับภาษา ขั้นตอนที่จะต้องเจอบ่อย ๆ คือการแทนคำด้วยหมายเลขประจำตัว (id หรือ index) ซึ่งเราต้องกำหนดให้แต่ละคำใน vocabulary นั้นไม่ซ้ำกัน
สมมติว่าเรามีลิสต์ของคำทั้งหมดในคลังข้อมูล เราต้องการสร้างดิกที่ key เป็นคำ และ value เป็นหมายเลขประจำตัวของคำคำนั้น
word_list = ['baby', 'baby', 'baby', 'oh', '...', 'baby', 'baby', 'no','!']
word_to_index = {}
for word in word_list:
if word not in word_to_index:
word_to_index[word] = len(word_to_index)
print(word_to_index)
#ผลลัพธ์ : {'baby': 0, 'oh': 1, '...': 2, 'no': 3, '!': 4}
เราสามารถเขียนโดย dict comprehension ให้กระชับขึ้นดังนี้
word_list = ['baby', 'baby', 'baby', 'oh', '...', 'baby', 'baby', 'no','!']
word_set = set(word_list)
word_list = list(word_set) # ทำให้เหลือเฉพาะคำที่ไม่ซ้ำ
word_to_index = {word:index for index, word in enumerate(word_list)}
print(word_to_index)
#ผลลัพธ์ : {'...': 0, 'baby': 1, 'oh': 2, '!': 3, 'no': 4}
สรุปข้อดี ข้อเสียของการใช้คอมพริเฮนชัน#
ข้อดีของการใช้ comprehension คือ
โค้ดสั้นกระชับสวยงาม ทำให้มีโอกาสเขียนโค้ดผิดน้อยลง เมื่อเทียบกับการใช้ for loop ในการแก้ปัญหาเดียวกัน
เร็วกว่าการใช้ for loop มาก เนื่องจากไพทอนจะทำการ optimize โค้ดให้สำหรับ comprehension
ข้อเสียของการใช้ comprehension คือ
ผู้ที่ไม่ได้คล่องการเขียนโค้ดด้วยภาษาไพทอนอาจจะอ่านไม่เข้าใจ เนื่องจากไม่มีภาษาคอมพิวเตอร์อื่นที่มีหรือนิยมใช้ comprehension
ถ้า expression ที่อยู่ใน comprehension ซับซ้อน จะทำให้อ่านได้ยาก ในกรณีนี้เราอาจจะเลี่ยงไปใช้ for loop แทน
สรุป#
ในบทนี้เราได้สำรวจการใช้โครงสร้างข้อมูลที่สำคัญ ได้แก่ ลิสต์ ดิกชันนารี และเซต ซึ่งเป็นเครื่องมือสำคัญในการจัดการข้อมูลที่หลากหลาย ลิสต์ช่วยให้เราจัดเก็บข้อมูลในลำดับที่ยืดหยุ่นและเข้าถึงได้โดยดัชนี ดิกชันนารีช่วยให้เราจัดการข้อมูลในรูปแบบคู่คีย์-ค่า ทำให้การค้นหาและจัดการข้อมูลที่มีโครงสร้างซับซ้อนมีประสิทธิภาพมากขึ้น ส่วนเซตช่วยในการเก็บข้อมูลที่ไม่ซ้ำและตรวจสอบสมาชิกภาพอย่างรวดเร็ว การเข้าใจและเลือกใช้โครงสร้างข้อมูลที่เหมาะสมจะช่วยให้เราพัฒนาโปรแกรมที่มีประสิทธิภาพและจัดการกับข้อมูลได้อย่างมีระบบ