Data Warehouse

การจัดการกับลิสต์ (List)

ในบทนี้จะมาขยายความถึงลิสต์ ซึ่งเป็นข้อมูลชนิดลำดับที่ใช้มากที่สุดเนื่องจากสามารถเพิ่มและแก้ไขข้อมูลได้ตลอด ต่างกับทูเพิลซึ่งแก้อะไรไม่ได้ สิ่งที่จะแนะนำในบทนี้เป็นคำสั่งที่ใช้กับลิสต์เป็นหลัก แต่บางอย่างก็สามารถนำมาใช้กับทูเพิลได้ด้วยเช่นกัน

การกลับลำดับลิสต์

สามารถกลับลำดับของสมาชิกในลิสต์จากหัวมาท้ายได้โดยใช้ for สร้างลิสต์ใหม่ที่ดึงข้อมูลลิสต์เดิมที่ไล่ตำแหน่งจากท้ายมาหัว เช่น

a = ['ก','ข','ค','ง','จ']  
b = [a[4-i]  for  i  in  range(len(a))]  
print(b)  # ['จ', 'ง', 'ค', 'ข', 'ก']

อย่างไรก็ตาม มีวิธีที่สามารถสลับลำดับของสมาชิกได้ในทันที นั่นคือใช้เมธอด reverse

a = ['ก','ข','ค','ง','จ']  
a.reverse()  
print(a)  # ได้['จ', 'ง', 'ค', 'ข', 'ก']

วิธีนี้ยังมีข้อดีตรงที่เป็นการเปลี่ยนสลับลำดับของสมาชิกในลิสต์เดิมไปเลยทันที ไม่ต้องสร้างลิสต์ขึ้นมาใหม่ ข้อเสียคือลิสต์แบบเดิมหายไป นอกจากนี้ยังอาจใช้ฟังก์ชัน reversed อย่างไรก็ตามฟังก์ชันนี้ไม่ได้ให้ผลเป็นลิสต์

a = ['ก','ข','ค','ง','จ']  
print(reversed(a))  # ได้ <list_reverseiterator object at 0x10de03198>

จะเห็นว่าผลที่ได้ไม่ใช่ลิสต์ที่ถูกสลับตำแหน่งข้อมูล แต่เป็นออบเจ็กต์อีกชนิดหนึ่งชื่อชนิด list_reverseiterator ซึ่งเป็นอิเทอเรเตอร์ (iterator) ชนิดหนึ่ง เวลาสั่งให้แสดงผลจะไม่สามารถเห็นผลได้ทันที

อย่างไรก็ตามสามารถนำมาใช้ใน for ได้เหมือนกับลิสต์ ละจะเห็นว่าตำแหน่งถูกสลับจากหลังมาหน้าจริงๆ

for  i  in  reversed(['ก','ข','ค','ง','จ']):  
print(i,end=' ')  
# ได้ จ ง ค ข ก

หรืออาจเปลี่ยนให้เป็นลิสต์ธรรมดาได้โดย

list(reversed(('ก','ข','ค','ง','จ')))  #ได้ ['จ', 'ง', 'ค', 'ข', 'ก']

วิธีนี้ใช้กับทูเพิลได้เช่นกัน

tuple(reversed(('ก','ข','ค','ง','จ')))  # ได้ ('จ', 'ง', 'ค', 'ข', 'ก')

การหาค่าสูงสุดและต่ำสุดของลิสต์

หลักการหาค่าสูงสุดหรือต่ำสุดของสมาชิกที่อยู่ภายในลิสต์นั้น ให้นึกถึงนายพรานที่ไปล่าหมูป่าเพื่อทำเป็นอาหาร

นายพรานสามารถขนหมูป่ากลับได้แค่ตัวเดียว สมมุติว่าเข้าไปถึงเขาเจอหมูป่าตัวหนึ่งก็ฆ่าแล้วขนมา แต่ต่อมาก็เจอตัวใหม่ซึ่งใหญ่กว่า จึงตัดสินใจทิ้งตัวเก่าไป พอเดินไปต่อก็ฆ่าหมูป่าได้อีกตัว แต่ตัวนี้ตัวเล็กกว่าเขาจึงเดินผ่านไปโดยเก็บตัวเดิมไว้ หลังจากนั้นก็เดินเจอหมูป่าอีกหลายตัวแล้วก็ทำเหมือนเดิมคือถ้าเจอตัวใหญ่ กว่าก็ฆ่าแล้วเปลี่ยนไปถือตัวนั้น จนสุดท้ายนายพรานก็จะได้หมูป่าตัวใหญ่ที่สุดกลับบ้าน การหาค่าสูงสุดของลิสต์ก็ใช้หลักการเดียวกันนี้ ลองสร้างลิสต์ของน้ำหนักหมูป่าทั้งหมดในป่าแล้วใช้ for เพื่อไล่หาค่าน้ำหนักของตัวที่มากที่สุดดู

mupa = [50.9,89.3,62.7,101.2,70.4,129.3,94.9]  #น้ำหนักหมูป่า 7 ตัว  
mmax = mupa[0]  # ตั้งค่าสูงสุดเริ่มต้น  
i = 0  # ลำดับของค่าสูงสุดเริ่มต้น  
for  m  in  mupa:  # ทำการวนซ้ำตามจำนวนในลิสต์  
if(m>mmax):  # ถ้ามากกว่าค่าสูงสุดเดิม  
mmax = m  # ให้เปลี่ยนเป็นค่านั้น  
imax = i  # และเปลี่ยนลำดับด้วย  
i += 1  
print('ตัวที่ %d หนักสุด หนัก %.1f กก.'%(imax,mmax))

ผลลัพธ์

ตัวที่ 5 หนักสุด หนัก 129.3 กก.

อย่างไรก็ตาม มีฟังก์ชันที่ใช้หาค่าสูงสุดได้ทันที นั่นคือ max

print(max(mupa))  # ได้ 129.3

และในทางกลับกันก็สามารถหาค่าต่ำสุดได้ด้วย โดยใช้ฟังก์ชัน min

print(min(mupa))  # ได้ 50.9

แต่ฟังก์ชันนี้ไม่สามารถบอกลำดับของข้อมูลที่ให้ค่าสูงสุดหรือต่ำสุดได้ ต้องใช้คู่กับฟังก์ชัน index เพื่อหาว่าตัวที่ตำแหน่งไหนมีค่าเป็นค่าสูงสุด

print(mupa.index(max(mupa)))  # ได้ 5

หรือเขียนแบบนี้ก็ได้

print(max(mupa, key=mupa.index))  # ได้ 5

การใช้เมธอด index นี้เหมือนกับ index ที่ใช้กับสายอักขระซึ่งอธิบายไปในบทที่แล้ว แต่ลิสต์จะไม่มี rindex และไม่มี find กับ rfind ด้วย

ผลรวมและค่าเฉลี่ยของตัวเลขในลิสต์

หากมีลิสต์ที่ประกอบไปด้วยจำนวนตัวเลข สามารถหาค่ารวมของสมาชิกในลิสต์ทั้งหมดได้โดยใช้ for ไล่สมาชิกทีละตัวแล้วให้บวกไปเรื่อย ๆ

x = [124.3,45.4,34.5,199.8,444.3,322.2,401.1]  
ruam = 0  
for  s  in  x:  
ruam +=s  
print(ruam)  # ได้ 1571.6

ส่วนค่าเฉลี่ยก็แค่นำความยาวของลิสต์มาหารอีกที

chalia = ruam/len(x)  
print('ค่าเฉลี่ยเท่ากับ %.2f'%chalia)  # ได้ ค่าเฉลี่ยเท่ากับ 224.51

ในภาษาไพธอนมีฟังก์ชันที่ใช้สำหรับหาค่าผลรวมของลิสต์โดยเฉพาะ คือ sum สามารถใช้เพื่อหาผลรวมและค่าเฉลี่ยได้ดังนี้

print(sum(x))  # ได้ 1571.6  
print(sum(x)/len(x))  # ได้ 224.5142857142857

นับจำนวนสิ่งที่ต้องการในลิสต์

หากต้องการหาว่าในลิสต์นั้นมีสมาชิกที่เราต้องการค้นอยู่กี่ตัวอาจทำได้โดยลองกำหนดตัวแปรขึ้นมาตัวหนึ่งใช้เก็บค่าจำนวนที่นับโดยเริ่มจาก 0 จากนั้นใช้ for วนเพื่อตรวจว่าสมาชิกแต่ละตัวตรงกับค่าที่ต้องการหรือไม่ ถ้าตรงก็บวกเพิ่มไปเรื่อย ๆ

ตัวอย่าง หาว่ามี 2 กี่ตัวในลิสต์ w

w = [1,2,1,2,2,2,1,2,2,1,1,1,1,2,1,1,2,2]  
nap = 0  
for  b  in  w:  
if(b==2): nap += 1  
print(nap)  # ได้ 9

นอกจากนี้ยังอาจทำได้ง่ายๆโดยใช้เมธอด count เช่นเดียวกับที่ใช้ในสายอักขระ

print(w.count(2))  # ได้ 9

การจัดเรียงลิสต์

วิธีการจัดเรียงสมาชิกในลิสต์ตามลำดับค่ามากน้อยนั้นมีอยู่หลายวิธี แต่วิธีที่เข้าใจง่ายที่สุดและนิยมสอนกันในเบื้องต้นก็คือการเรียงลำดับแบบฟอง (bubble sort) คือตรวจดูค่าแล้วสลับลำดับทีละคู่ไปเรื่อยๆ โดยไล่จากตัวแรกกับตัวที่สอง ไปตัวที่สองกับตัวที่สาม แล้วไล่ไปเรื่อยๆจนถึงตัวรองสุดท้ายกับตัวสุดท้าย จากนั้นก็วนสลับอย่างนี้ไปอีกเรื่อย ๆ จนเรียงกันหมด

x = [35,24,30,17,15,6,8,2]  
for  i  in  range(len(x)-1):  # ทำซ้ำไป len(x)-1 ครั้ง  
for  j  in  range(len(x)-i-1):  # ทำซ้ำโดยไล่ตั้งแต่ j เป็น 0 ไปจนถึง j เป็น len(x)-i-2  
if(x[j]>x[j+1]):  # ถ้าตัวซ้ายมากกว่าตัวขวาให้สลับ  
x[j],x[j+1] = x[j+1],x[j]  
print(x)

ผลลัพธ์

[24, 30, 17, 15, 6, 8, 2, 35]  
[24, 17, 15, 6, 8, 2, 30, 35]  
[17, 15, 6, 8, 2, 24, 30, 35]  
[15, 6, 8, 2, 17, 24, 30, 35]  
[6, 8, 2, 15, 17, 24, 30, 35]  
[6, 2, 8, 15, 17, 24, 30, 35]  
[2, 6, 8, 15, 17, 24, 30, 35]

อย่างไรก็ตามตามในทางปฏิบัติแล้วมีวิธีอื่นที่เร็วกว่า ตัวอย่างนี้แค่ยกมาเพื่อฝึกกระบวนการคิดเท่านั้น ที่จริงแล้วในไพธอนมีคำสั่งเฉพาะที่ใช้ในการทำให้สมาชิกของลิสต์เรียงกันทันทีโดยง่าย นั่นคือเมธอด sort

x = [35,24,30,17,15,6,8,2]  
x.sort()  
print(x)  # ได้ [2, 6, 8, 15, 17, 24, 30, 35]

ซึ่งจะพบว่านอกจากจะเขียนง่ายกว่าแล้วยังทำงานเร็วกว่ามากอย่างเทียบไม่ติด ดังนั้นในทางปฏิบัติแล้วจึงควรใช้วิธีนี้มากกว่า หากต้องการเรียงกลับด้านก็เพิ่มคีย์เวิร์ด reverse เข้าไปเป็น reverse=True (หรือใช้ 1 แทน True ก็ได้)

x = [35,24,30,17,15,6,8,2]  
x.sort(reverse=1)  
print(x)  # ได้ [35, 30, 24, 17, 15, 8, 6, 2]

นอกจากนี้ยังอาจใช้ฟังก์ชัน sorted ซึ่งจะคืนค่าลิสต์ที่เรียงแล้ว

x = [35,24,30,17,15,6,8,2]  
print(sorted(x))  # ได้ [2, 6, 8, 15, 17, 24, 30, 35]

อนึ่ง ฟังก์ชัน sorted ไม่ได้เป็นการแก้ไขตัวลิสต์แต่เป็นการสร้างลิสต์ใหม่โดยใช้สมาชิกของลิสต์เก่ามาจัดเรียง ดังนั้นทูเพิลก็สามารถใช้ฟังก์ชัน sorted ได้ แต่ผลที่ไดจะออกมาเป็นลิสต์ ต้องแปลงกลับเป็นทูเพิลอีกที

y = (489,378,112,388,98,14,333)  
y =  tuple(sorted(y))  
print(y)  # ได้ (14, 98, 112, 333, 378, 388, 489)

การสร้างคีย์ในการเรียงขึ้นเอง

ในการเรียงนั้นปกติหากเป็นตัวเลขก็จะเรียงตามค่าสูงต่ำ หากเป็นตัวอักษรก็จะเรียงตามลำดับในยูนิโค้ด แต่ก็สามารถตั้งคีย์ขึ้นมาเองเพื่อใช้เป็นดัชนี ในการค้นได้เช่นกัน โดยการเพิ่มคีย์เวิร์ด key ลงไปในฟังก์ชัน sorted ดัชนีที่ใช้อาจเป็นสายอักขระหรือลิสต์ก็ได้
ตัวอย่าง ลองทำให้อักษรเรียงตามลำดับในแป้นพิมพ์เกษมณีโดยไล่จากแถวบนไปแถวล่าง ซ้ายไปขวา

kedma =  'ภถคตจขชฎพฑธรณนยญบฐลฃฅฟหฆกฏดฌษสศวซงผปฉอฮทมฒฬฝ'  
a = ['ก','ข','ค','ฆ','ง','จ','ฉ','ช','ซ']  
print(sorted(a,key=kedma.index))

ได้

['ค', 'จ', 'ข', 'ช', 'ก', 'ซ', 'ง', 'ฉ']

สรุปเนื้อหา

ในบทนี้ได้พูดถึงกระบวนการจัดการกับสมาชิกภายในลิสต์แบบต่างๆทั้งแบบใช้ฟังก์ชันหรือเมธอดช่วยและแบบที่ไม่ใช้ การใช้ฟังก์ชันหรือเมธอดช่วยนั้นจะง่ายกว่า แต่เพื่อให้เข้าใจหลักการคิดและกระบวนการที่ซ่อนอยู่ภายในจึงอธิบายวิธีที่เห็นภาพชัดก่อน
เรื่องของลิสต์นั้นยังมีรายละเอียดอีกมาก ที่แนะนำมาจนถึงตอนนี้เป็นแค่พื้นฐานส่วนหนึ่ง ที่เหลือต้องนำไปต่อยอดกันต่อไป

อ้างอิง
http://docs.python.jp/3/library/stdtypes.html
http://www.tohoho-web.com/python/list.html
http://minus9d.hatenablog.com/entry/2015/01/04/235442
http://kaisk.hatenadiary.com/entry/2014/11/04/232558
http://d.hatena.ne.jp/yumimue/20071218/1197985024
https://ja.wikipedia.org/wiki/バブルソート

Reference : https://phyblas.hinaboshi.com/tsuchinoko12