หลังจากในตอนที่แล้วผมได้มีการแนะนำแนวทางการใช้ Python ใน Excel เบื้องต้นไปแล้ว ในตอนนี้หลักๆ แล้ว ผมจะมาแนะนำวิธีเขียน Code เพื่อสร้าง Loop ใน Python ให้เพื่อนๆ ได้รู้จักกันครับ
Loop คือการสั่งให้โปรแกรมคอมพิวเตอร์ทำงานซ้ำๆ ตามที่เรากำหนด ซึ่งใน python มี Loop แบบนึงที่นิยมมาก คือ for loop ซึ่งค่อนข้างทรงพลังมาก
วิธีการคือ for loop จะวนพิจารณาทำงานซ้ำโดยอ่านค่า Item ใน Object ที่มี item ย่อยๆ อยู่ข้างใน ที่ใช้บ่อยมากคือ List Range กับ String (ข้อความ) เป็นต้น ซึ่งเป็นเรื่องที่ผมจะอธิบายในบทความนี้
แต่ก่อนที่ผมจะอธิบายเรื่อง Loop เพื่อให้เห็นภาพมากขึ้น เรามาทำความรู้จัก List ให้ดีขึ้นกันอีกนิดนึงดีกว่าครับ
สารบัญ
เรื่องของ List ใน Python
List คือประเภทข้อมูลแบบนึงของ Python ที่สามารถเก็บข้อมูลไว้ในตัวมันได้หลายตัว โดยที่ข้อมูลแต่ละตัวจะเป็นข้อมูลประเภทอะไรก็ได้ (ใน List มี List ซ้อนอีกก็ได้) เก็บซ้ำกันก็ได้ และลำดับการเก็บข้อมูลมีความหมาย (เราอ้างอิงตำแหน่งของมันได้)
สมมติว่า List ต้นฉบับคือแบบนี้
colorList=["red","green","blue","yellow"]
อ้างอิงถึง item ใน List
หากเราต้องการอ้างอิงถึง item ใน List สามารถใช้
ListName[เลขindex]
โดยที่เราสามารถอ้างอิงเลข index ได้ 2 แบบ คือ
- เลข index เป็นบวก โดยเริ่มจาก item แรก คือ index 0 คือ แล้ว item 2 คือ index 1
- เลข index ติดลบ ไล่ย้อนหลับนับ item สุดท้ายเป็น -1, รองสุดท้ายคือ -2
เช่น
- colorList[1] จะได้ item ที่ 2 คือ string ว่า green
- colorList[-3] คือ item ลำดับที่ 3 จากท้าย ซึ่งในที่นี้ก็คือ green เช่นกัน
Slice หั่นเลือกเอาช่วง item ใน List
เราสามารถ slice เลือกบางส่วนของ List ได้ด้วยวิธีแบบนี้
ListName[ indexเริ่ม : แต่ไม่ถึง indexจบ ]
colorList[1:3]
# เอาตั้งแต่ index1 (เริ่มตัวที่2) แต่ไม่ถึง index3 (ไม่ถึง 4 คือเอาถึงตัวที่3)
สรุปแล้ว [1:3] แปลว่าเอาตั้งแต่ ตัวที่2 ถึงตัวที่ 3
ถ้าจะเริ่มเอาแต่แรก สามารถใส่ colorList[0:3] หรือจะเว้นไปเลย เหลือแค่ colorList[:3] ก็ได้
colorList[:3]
# เอาตั้งแต่แรก แต่ไม่ถึง index3 (ไม่ถึง 4 คือเอาถึงตัวที่3)
สรุปแล้ว [:3] แปลว่าเอาตั้งแต่ ตัวแรก ถึงตัวที่ 3
ถ้าจะเอาถึงตัวสุดท้าย ก็เว้นการใส่ตัวสุดท้ายไปเลยก็ได้ เช่น
colorList[1:]
# เอาตั้งแต่ index1 (เริ่มตัวที่2) จนถึงตัวสุดท้าย
สรุปแล้ว [1:] แปลว่าเอาตั้งแต่ตัวที่2 ถึง ตัวสุดท้าย
แล้วก็สามารถใส่ index ติดลบได้เช่นเดิม
colorList[1:-1]
# เอาตั้งแต่ index1 (เริ่มตัวที่2) แต่ไม่ถึง index -1 (ไม่ถึงตัวสุดท้าย คือเอาถึงตัวรองสุดท้าย)
สรุปแล้ว [1:-1] แปลว่าเอาตั้งแต่ตัวที่2 ถึง ตัวรองสุดท้าย
การรวม List เข้าด้วยกัน
เราสามารถรวม Item ใน List เข้าด้วยกันได้ด้วยเครื่องหมาย + ธรรมดาเลย simple สุดๆ เช่น
MyList1=["red","green","blue"]
MyList2=[55,20,200]
combinedList=MyList1+MyList2
แต่ถ้าจะมัดรวมเป็นคู่อันดับ ให้ใช้ zip มาช่วย เช่น
MyList1=["red","green","blue"]
MyList2=[55,20,200]
zipObject=zip(MyList1,MyList2)
zipList=list (zipObject)
print(zipList)
เริ่มทำการวน Loop
พอเราเริ่มรู้จัก List ที่เป็น Object ประเภทนึงที่สามารถเก็บข้อมูลหลาย item ในตัวมันเองแล้ว เราลองมาเริ่มดูวิธีวน Loop กันบ้าง
โดยโครงสร้างของ for loop ใน Python เป็นแบบนี้
for item in Objectที่มีSequence: # ต้องมี : ด้วย
คำสั่งใน loop ที่จะให้ทำซ้ำ #ต้องมี tab เพื่อย่อหน้าเข้ามา 1 ทีด้วย
คำสั่งใน loop ที่จะให้ทำซ้ำ #ต้องมี tab เพื่อย่อหน้าเข้ามา 1 ทีด้วย
คำสั่งที่ไม่เกี่ยวกับ loop #ถ้าไม่มีย่อหน้าคือไม่อยู่ใน loop
วน Loop ใน List
สมมติถ้าอยากจะวน Loop ใน colorList ที่สร้างไว้ แล้วพยายาม print เอาข้อมูลสีออกมาในแบบตัวพิมพ์ใหญ่
โดยผมลองเขียนให้ดู เพื่อทำความเข้าใจแบบละเอียด ดังนี้
เราสามารถจะตั้งชื่อตัวแปรที่เอาไว้วน Loop (ตัวที่อยู่หลัง for) ว่าอะไรก็ได้ เช่น i, x, num, char, color, blahblah หรืออะไรก็ได้
ซึ่งในที่นี้เราตั้งว่า color โดยการวน loop แต่ละรอบ ตัวแปร color นี้ก็จะเปลี่ยนไปเรื่อยๆ โดยรับค่าที่เป็นข้อความ “red” “green” “blue” “yellow” เปลี่ยนไปเรื่อยๆ ทีละตัว
การที่เราจะทำให้เป็นตัวพิมพ์ใหญ่ เราสามารถใช้ method ที่ชื่อว่า .upper() มาช่วยได้
เพราะมันคือ Method ที่ถูกฝังไว้ใน object ประเภท String หรือข้อความนั่นเอง ซึ่งชื่อสีของเราเป็นข้อความก็ต้องใช้คำสั่งนี้ได้
for color in colorList:
UpColor=color.upper() #สร้างตัวแปร UpColor มาเก็บตัวพิมพ์ใหญ่
print(UpColor) #print UpColor ออกมาใน Console
print("นี่คือนอก loop")
ผลที่ได้ คือ จะมีการ print ชื่อสีแต่ละอันเป็นตัวพิมพ์ใหญ่ ออกมาใน console ซึ่งใน Excel มันจะถือว่า Console อยู่ในส่วนของ Diagnostics ด้านขวา (ลากออกมาได้นะ)
เราจะพบว่า มีการ Print สีจำนวน 4 ครั้ง (เพราะเรามีทั้งหมด 4 สี มันไล่วน Loop Print แต่ละสี สีละ 1 ครั้ง) แต่มีการ Print คำว่า “นี่คือนอก loop” แค่ 1 ครั้ง เพราะเราใส่ไว้โดยไม่มีการย่อหน้า แสดงว่าไม่อยู่ใน loop แล้ว
เอาจริงๆ การวน loop print เราเขียนแค่นี้ก็พอ ไม่ต้องประกาศอะไรเยอะแยะ
for color in colorList:
print(color.upper())
แต่ถ้าเราอยากให้มันออกมาใน Cell เป็น Dynamic Array เราต้องทำให้ผลลัพธ์เป็น List ก่อน Excel จึงจะเข้าใจ ถ้าปล่อยเป็น NoneType จะเอาออกมาไม่ได้
วิธีการแบบนึงที่ทำได้คือ สร้าง List ว่างเปล่าขึ้นมาก่อน แล้ววน Loop เอา item แต่ละอันใส่ เข้าไปใน List ด้วย .append() แล้วค่อยเรียก List นั้นออกมาอีกที ดังนี้ (แล้วอย่าลืมแก้ Output ให้เป็น Excel Value ด้วย)
UpperColorList=[] #สร้าง UpperColorList ว่างเปล่า
for color in colorList:
UpperColorList.append(color.upper()) #ใส่ item เพิ่มใน List
UpperColorList #แสดง UpperColorList ออกมา
List Comprehension
อย่างไรก็ตาม เราสามารถสร้าง List ใหม่ได้ง่ายๆ กว่าที่เขียนข้างบน ด้วยเทคนิคที่เรียกว่า List Comprehension ซึ่งเหมือนการเขียน for loop แบบย่อสุดๆ ที่ให้ผลเป็น List ใหม่ได้เลย โดยไม่ต้องมานั่งเขียน code ยาวๆ เช่น
ในรูปแบบของ
[itemผลลัพธ์ for item in Objectที่มีSequence]
เช่น
[color.upper() for color in colorList]
เดี๋ยวเราลองไปดูการวน Loop ใน item อื่นที่ไม่ใช่ List โดยตรงบ้าง
วน Loop ใน Range
ถ้าเราอยากจะวน Loop กับ ตัวเลข 6 ตัว ที่เริ่มจากเลข 0 เราสามารถใช้ฟังก์ชัน range(6) ได้ ซึ่งมันคือ Object ที่คล้าย List ที่ประกอบไปด้วย item 0,1,2,3,4,5 อยู่ข้างในนั่นเอง
ลองให้มันสั่ง print เลข 0-5 ออกมาใน console โดยที่ตั้งตัวแปร i ขึ้นมาแทนแต่ละเลขขณะวน Loop
for i in range(6):
print(i)
แต่ถ้าเราอยากให้มันออกมาใน Cell เป็น Dynamic Array ก็ใช้ List Compreshension ก็ได้ ง่ายดี
[i for i in range(6)]
เราจะได้ผลลัพธ์เป็น List ใหม่ทันที ง่ายๆ แบบนี้เลย
หรือถ้าอยากได้เลขที่ไม่ได้เริ่มจาก 0 ก็สามารถทำแบบนี้ได้ ในรูปแบบของ
range(เลขเริ่ม,แต่ไม่ถึงเลขจบ)
เช่น
[i for i in range(3,10)]
แบบนี้คือ 3 ถึง 9 (เลขจะไม่รวม 10)
และถ้าอยากจะเพิ่ม step มากกว่า 1
range(เลขเริ่ม,แต่ไม่ถึงเลขจบ,step)
เช่น เพิ่มทีละ 2 ก็ทำแบบนี้ได้ คือใส่ ,2 ต่อไปอีก
[i for i in range(3,9,2)]
กลับมาที่ range(6) คือ เลข 0-5 อีกที…
ถ้าผลลัพธ์ที่เราต้องการไม่ได้เป็นการสร้าง List ใหม่ ก็อาจจะไม่ต้องใช้ List Comprehension ก็ได้
เช่น ลองสร้างเลขบวกสะสมกันไปเรื่อยๆ ตั้งแต่ 0-5
x=0
for i in range(6):
x=x+i
x
หรือเอาจริงๆ จะทำ List Comprehension เพื่อสร้าง List ผลลัพธ์ก่อน (ในทีนี้ผมเก็บไว้ในตัวแปร MyList) แล้วค่อย Sum ค่าใน List ทั้งหมดก็ได้ เช่น
MyList=[i for i in range(6)]
x = sum(MyList)
วน Loop ใน String
นอกเหนือจากการวน Loop ใน List และใน Range แล้ว เรายังสามารถวน Loop ใน String หรือข้อความได้ด้วย ซึ่งมันคือ การวนพิจารณาทีละอักขระของข้อความได้เลย ซึ่งทรงพลังมากๆ
MyList=[] #สร้าง List ว่างเปล่า
for char in "thepexcel":
MyList.append(char) #ใส่แต่ละอักขระเพิ่มเข้าไปใน List
MyList #แสดง MyList ออกมา
ซึ่งใช้ List Comprehension ง่ายกว่าเยอะ
MyList=[char for char in "thepexcel"]
การใส่ Condition
เราสามารถจะใช้ if เพื่อสร้าง condition บางอย่างได้
กรณีถ้าเงื่อนไขจริงแล้วให้ทำอะไรบางอย่าง (ถ้าไม่ตรงก็ไม่ทำอะไร)
if condition:
#action1 if true
#action2 if true
เช่น
ผมทำให้ดู 2 เคสเลย ว่ากรณีเงื่อนไขเป็นจริง ก็จะทำตาม action ที่กำหนด แต่ถ้าไม่ตรงตามเงื่อนไขก็จะไม่มีอะไรเกิดขึ้น
result1="original1"
score=45
if score>10:
result1="score1 มากกว่า 10"
result2="original2"
score=5
if score>10:
result2="score2 มากกว่า 10"
[result1,result2]
การเขียน if แบบนี้ ซึ่งถ้าผลลัพธ์มีแค่ 1 action เราสามารถย่อได้ จะได้ไม่ต้องปวดหัวกับการ indent ย่อหน้าเข้าไป
if condition: action_if_true
เช่น อันนี้ผมทำเคสจริงให้ดูอย่างเดียว
result1="original1"
score=45
if score>10:result1="score1 มากกว่า 10"
result1
กรณีถ้าเงื่อนไขจริงแล้วให้ทำอะไรบางอย่าง ถ้าไม่จริงให้ทำอีกอย่าง
ก็คือนอกจากจะมี if แล้ว คราวนี้ต้องมี else เพื่อทำกรณีที่ไม่จริงด้วย ซึ่งโครงสร้างคือ
if condition:
#action if true
else:
#action if false
เช่น
result="original"
score=5
if score>10:
result="score มากกว่า 10"
else:
result="score ไม่ได้มากกว่า 10"
result
ซึ่งถ้าแต่ละเงื่อนไขมีแค่ 1 action เราสามารถย่อได้เช่นกัน ในรูปแบบนี้ คือไม่มี : ไม่มีย่อหน้าเลยด้วย แต่จะมีการสลับเอา action กรณีจริงขึ้นมาก่อน
action_if_true if condition else action_if_false
แต่ action ในรูปแบบนี้จะใช้การ assign ตัวแปรไม่ได้นะ ดังนั้นผมจะใช้การ print เพื่อพิสูจน์ให้ดูแทน
score=5
print("score มากกว่า 10") if score>10 else print("score ไม่ได้มากกว่า 10")
ลองใช้ condition ใน Loop
เราลองมาดูตัวอย่างการใช้ Condition ใน Loop กัน
สมมติว่า เราจะวน Loop ใน String เพื่อพิจารณาแต่ละอักขระ ถ้าพบว่าอักขระที่กำลังพิจารณา (char) เป็นตัว e เราจะให้ทำเป็นตัวพิมพ์ใหญ่ โดยใช้ method .upper() ภายใน condition ของ if
MyList=[] #สร้าง List ว่างเปล่า
for char in "thepexcel":
if char =="e":
char=char.upper() #ถ้าเป็นตัว e ให้ทำเป็นพิมพ์ใหญ่
MyList.append(char) #ใส่แต่ละอักขระเข้าไปใน List
MyList #แสดง MyList ออกมา
แต่ถ้าในกรณีนี้เราทำด้วย List Comprehension แบบทื่อๆ เลย การเขียน condition if แบบย่อแค่ action จริง จะไม่ work ในกรณีนี้
MyList=[char.upper() for char in "thepexcel" if char=="e" ]
เพราะว่ามันดันเป็นการสร้าง List ใหม่ โดย “คัดเลือกเฉพาะที่ตรงกับเงื่อนไข” ที่กำหนดคือเป็นตัว e เท่านั้น (กลายเป็นได้ E 3 ตัวเฉยเลย นั่นคือ กรณี False จะไม่มีการเอามาใส่ใน List)
ถ้าอยากให้มีทุกตัวเท่าเดิม เราควรกำหนดทั้งกรณีทั้ง True และ False แต่โครงสร้างของ List Comprehension จะเปลี่ยนไปนิดหน่อย กลายเป็น if else ซึ่งจะมีการสลับตำแหน่ง
MyList=[char.upper() if char=="e" else char for char in "thepexcel" ]
แบบนี้ถึงจะ work ได้ตามต้องการครับ
ลองการประยุกต์
วน Loop เพื่อแก้ชื่อคอลัมน์ของ DataFrame
สมมติผมมี DataFrame อยู่ แล้วอยากจะได้ชื่อคอลัมน์ออกมาเป็น List ผมสามารถทำได้แบบนี้
df = xl("IrisDataSet[#All]", headers=True)
dfColList=list(df.columns)
ทีนี้ผมอยากจะวน Loop เพื่อทำการแก้ชื่อคอลัมน์เฉพาะที่มีเครื่องหมาย _ ให้เป็นพิมพ์ใหญ่
ผมทำได้ดังนี้
NewdfColList=[ col.upper() if "_" in col else col for col in dfColList ]
แล้วเราก็เอาชื่อคอลัมน์ใหม่ assign เข้าไปใน df เดิมก็ได้ ดังนี้
df.columns = NewdfColList
df
จริงๆ ก็คือเขียนรวมกันหมดเลยใน code ของ cell เดียวก็ได้นะ เช่น
df=xl("IrisDataSet[#All]", headers=True)
dfColList=list(df.columns)
NewdfColList=[ col.upper() if "_" in col else col for col in dfColList ]
df.columns = NewdfColList
df
คัดเลือกให้แสดง DataFrame แค่บางคอลัมน์
ทีนี้ในเมื่อเราจัดการ List เป็นแล้ว อาจใช้มันในการเลือก List ที่ต้องการก็ได้ เช่น ผมต้องการ Columnที่ 1,4,5 เสมอ ผมอาจใช้แบบนี้
SelectCol=[NewdfColList[i-1] for i in [1,4,5]]
แล้วผมค่อยเอา List รายชื่อคอลัมน์นี้ใส่เข้าไปใน DataFrame เพื่อเป็นการคัดเลือกเอาคอลัมน์ที่ต้องการได้เลย เช่น
df[SelectCol]
ตอนต่อไป
สำหรับตัวอย่างนี้ก็ค่อนข้างยาวแล้ว ผมขอจบเพียงเท่านี้ ในตอนต่อไปเราจะพูดถึงเรื่อง Regular Expression กันครับ ซึ่งคือเรื่องที่ Python ชนะ Excel แบบขาดลอยของจริงครับ หึหึ