Tutorial

Comparison Operators กับ List และ Iterable อื่น ๆ บน Python

By Arnon Puitrakul - 17 มกราคม 2022

Comparison Operators กับ List และ Iterable อื่น ๆ บน Python

เรื่องนึงที่เราว่ามันเป็น Hidden หรือไม่ก็ Unseen สำหรับเรา เวลาเราใช้งาน Python เลย ตอนรู้จักครั้งแรกคือ ห่ะ แบบนี้ก็ได้เหรอ คือ การใช้พวก Comparison Operators อย่าง เท่ากับ มากกว่า น้อยกว่า อะไรพวกนั้น กับ Iterable ต่าง ๆ อย่างพวก List และ Set อะไรพวกนั้นได้ด้วย วันนี้เราลองมาดูกัน

Set

x = {1, 2, 3}
y = {2, 3, 4, 5}

z = x.issubset(y) 

เราขอเริ่มจากตัวที่เข้าใจง่ายที่สุดก่อน อย่าง Set ถ้าใครที่เคยใช้ Set ใน Python น่าจะคุ้นเคยกันดี ซึ่งหนึ่งในสิ่งที่เราจะเช็ค เราอาจจะเช็คพวก Subset และ Superset อะไรพวกนั้นกับ Set อีกตัว ซึ่งใน Python เอง เราก็สามารถที่จะเช็คได้ผ่านคำสั่ง issubset() ได้เลยอะไรแบบนั้น แต่เราจะเห็นว่า เออ มันก็ดูรก ๆ หน่อย มันน่าจะดีมาก ๆ ถ้ามี Shorthand ให้เราสามารถใช้ได้ พูดมาขนาดนี้ ใช่แล้วละ เราสามารถใช้ Comparison Operators ได้

>>> {1} == {1}
True

>>> {1} < {1,2}
True

>>> {1,2} < {1}
False

>>> {1,3} < {1,2}
False

ดูผ่าน ๆ อาจจะ งง นิด ๆ ทริกง่าย ๆ คือ เท่ากันหมายความว่า Set ทั้ง 2 มี Member เหมือนกันทุกตัว 100% ทำให้มันเท่ากัน ส่วนเครื่องหมาย มากกว่า น้อยกว่า มองง่าย ๆ ว่า ด้านที่น้อยกว่าเป็น Subset ของอีกด้านหรือไม่ ทำให้ในตัวอย่างที่ 2 เป็นจริง เพราะ 1 ของด้านซ้าย อยู่ใน Set ด้านขวาที่เอามาเปรียบเทียบ แต่ในตัวอย่างที่ 3 มองกลับกัน 2 ของด้านซ้าย ไม่ได้อยู่ใน Set ด้านขวา ทำให้ Set ด้านขวา ไม่ได้เป็น Superset ของ Set ด้านซ้ายทำให้ได้ False ไป และตัวอย่างสุดท้าย คือตัวอย่างที่ 4 อันนี้ไม่เป็นจริงใน 2 Member คือ 3 ในฝั่งซ้ายไม่ได้อยู่ในฝั่งขวา และ 2 ในฝั่งขวา ไม่ได้อยู่ในด้านซ้าย ทำให้ไม่เป็นจริงได้ False ออกมา

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

List และ Iterator อื่น ๆ

สาเหตุที่เราไม่เอา List ที่ดูจะเป็น Data Structure ที่ง่ายที่สุดขึ้นก่อน เพราะ มันเป็นตัวที่ปวดหัวมาก ๆ เพราะสิ่งที่มันจะเช็คคือ ตัวไหนมาก่อน หรือก็คือเป็น Lexicographic order บางคนก็เรียก Dictionary Order ก็ว่ากันไป เอาง่าย ๆ อย่าง String กันก่อน

>>> "brand" < "black"
False

เราเทียบง่าย ๆ เลย คือคำว่า Brand กับ Black ถ้าเราเอาน้อยกว่ามาใส่ มันจะเป็นจริงได้ก็ต่อเมื่อ Brand มาก่อน Black ใน Dictionary เทียบง่าย ๆ คือ ตัวแรก มันเท่ากัน เพราะคือตัว B เหมือนกัน แต่ตัวที่ 2 นี่แหละ ตัดเชือกละ สาเหตุที่มันเป็น False เพราะ L ที่อยู่ใน Black มันมาก่อน ตัว R ใน Brand ทำให้ Brand มันเลยมากกว่านั่นเอง แค่นี้เลย

>>> ["b", "r"] < ["b", "l"]
False

>>> [1,2] < [2,2]
True

ถ้าเราจำกันได้ จริง ๆ แล้ว String มันก็เป็นเหมือน List ที่มีแค่ Character และถ้าเราเห็นพฤติกรรมจากตัวอย่างก่อนหน้าแล้ว เราก็จะเดาของ List ได้ไม่ยากเลย เราเอาตัวอย่างเดิมมาเลย แต่เราใช้แค่ 2 ตัวแรก ก็รู้เรื่องแล้ว เราก็จะได้ผลลัพธ์เหมือนกันเป๊ะ ๆ เลย

งั้นเอาใหม่ เราลองมาเป็นอะไรที่เข้าใจง่ายกว่านั้นหน่อย เราเอา คู่ของ 1,2 และ 2,2 มา โดยเทียบกันผ่านเครื่องหมายน้อยกว่า มันก็จะเป็นจริง เพราะ 2 ในตัวแรกของฝั่งขวา มันมาทีหลัง 1 ที่เป็นตัวแรกของฝั่งซ้ายนั่นเอง

>>> [1] < [2,2]
True

ในตัวอย่างด้านบน เราทำให้ดูในกรณีที่จำนวนสมาชิกไม่เท่ากัน โดยเราจะเห็นว่า จริง ๆ แล้วมันไม่ได้แคร์จำนวนของสมาชิก หรือความยาวของ String ใด ๆ ทั้งสิ้น เพราะจริง ๆ แล้วมันจะค่อย ๆ เทียบทีละตัวไปเรื่อย ๆ จนได้ผลลัพธ์ออกมาว่า เป็นมากกว่าหรือน้อยกว่า หรือฝั่งใดฝั่งหนึ่งหมดก่อนมันจะออกมาเป็นเท่ากับ อย่างในกรณีนี้ เราจะเห็นว่า 1 ที่อยู่ใน List ด้านซ้ายมันมาก่อน 2 ที่เป็นตัวแรกของฝั่งขวา เลยทำให้ มันเป็นจริงนั่นเอง และแน่นอนว่า การเปรียบเทียบแบบนี้ เราสามารถใช้ได้กับ Tuple ก็ได้ด้วยเช่นกัน

>>> [1, 'a'] < [1, 'b']
True

อย่างที่เราบอกว่า มันจะเปรียบเทียบทีละตัวไปเรื่อย ๆ เราลองมาดูเคสที่ซับซ้อนมากกว่านี้กัน เราบอกว่า ใน List เรามี Member ที่เป็นคนละ DataType กัน ตัวนึงเป็น Integer และอีกตัวเป็น String โดยมันจะเริ่มเทียบจากตัวแรก ก็คือ 1 ของทั้ง 2 ด้าน มันเท่ากัน เลยผ่านไป ที่ตัวต่อไป คือ a และ b ซึ่งแน่นอนว่า b มาทีหลัง ทำให้ใน List นี้ฝั่งขวาเลยมากกว่าฝั่งซ้าย ทำให้มันเป็นจริงนั่นเอง

>>> [1, 3] < [1, 'b']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'

ไหน ๆ เราก็พูดถึงการเปรียบเทียบกับ List ที่มีหลาย ๆ DataType หนึ่งในอีกเคสที่เราเจอได้คือ เมื่อ DataType มันไม่เหมือนกัน อย่างที่บอกว่า 1 ของทั้ง 2 ฝั่ง ไม่ใช่ปัญหาเพราะมันเท่า แต่ปัญหามันจะไปอยู่ที่ 3 ของฝั่งซ้าย และ b ของฝั่งขวา เมื่อมันเปรียบเทียบกัน ตัว Python มันเทียบไม่ได้ ทำให้เจอ Error อย่างที่เห็นด้านบน

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

สรุป

การใช้ Comparison Operator กับพวก Iterable ต่าง ๆ ก็ถือว่าเป็น Shorthand ที่ทำให้เวลาเราเขียน Script ออกมา มันสั้นลงได้ ก็ตามหน้าที่ของ Shorthard แหละ นอกจากนั้นมันยังลดความซับซ้อนในการเขียน โดยเฉพาะใน Python เองที่เราสามารถทำ Comparison Operation Chaining หรือก็คือ การเทียบไปเรื่อย ๆ เช่น 1 > 2 > 3 ได้ อย่างใน Set เองถ้าเราเจอพวก Chaining แล้วหาพวก subset เราก็ต้องพ่วง issubset() ไปเรื่อย ๆ มันก็ไม่น่าอ่านเท่าไหร่ อ่าน ๆ ไป งง อ้าว อันไหนเริ่มก่อนหลังอะไรยังไง ดูไม่น่ารักเลย พวกนี้การใช้ Comparison Operator มันช่วยมาก ๆ แต่สำหรับในกรณีทั่ว ๆ ไป เรามองว่า ใช้เป็นพวก issubset() อะไรพวกนั้นเหมือนเดิม เข้าใจง่ายกว่าเยอะ แต่สำหรับ List และ Tuple เอง การใช้พวกนี้ เราว่ามันทำให้เราทำงานง่ายขึ้นมากจริง ๆ ก็ลองเอาไปใช้กันได้ ถือว่าเป็นทริกเล็ก ๆ น้อยใน Python

Read Next...

จัดการเรื่องแต่ละมื้อ แต่ละเดย์ด้วย Obsidian

จัดการเรื่องแต่ละมื้อ แต่ละเดย์ด้วย Obsidian

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

Loop แท้ไม่มีอยู่จริง มีแต่ความจริงซึ่งคนโง่ยอมรับไม่ได้

Loop แท้ไม่มีอยู่จริง มีแต่ความจริงซึ่งคนโง่ยอมรับไม่ได้

อะ อะจ๊ะเอ๋ตัวเอง เป็นยังไงบ้างละ เมื่อหลายเดือนก่อน เราไปเล่าเรื่องกันขำ ๆ ว่า ๆ จริง ๆ แล้วพวก Loop ที่เราใช้เขียนโปรแกรมกันอยู่ มันไม่มีอยู่จริง สิ่งที่เราใช้งานกันมันพยายาม Abstract บางอย่างออกไป วันนี้เราจะมาถอดการทำงานของ Loop จริง ๆ กันว่า มันทำงานอย่างไรกันแน่ ผ่านภาษา Assembly...

Monitor การทำงาน MySQL ด้วย Prometheus และ Grafana

Monitor การทำงาน MySQL ด้วย Prometheus และ Grafana

นอกจากการทำให้ Application รันได้แล้ว อีกเรื่องที่สำคัญไม่แพ้กันคือการวางระบบ Monitoring ที่ดี วันนี้เราจะมาแนะนำวิธีการ Monitor การทำงานของ MySQL ผ่านการสร้าง Dashboard บน Grafana กัน...

เสริมความ"แข็งแกร่ง" ให้ SSH ด้วย fail2ban

เสริมความ"แข็งแกร่ง" ให้ SSH ด้วย fail2ban

จากตอนที่แล้ว เราเล่าในเรื่องของการ Harden Security ของ SSH Service ของเราด้วยการปรับการตั้งค่าบางอย่างเพื่อลด Attack Surface ที่อาจจะเกิดขึ้นได้ หากใครยังไม่ได้อ่านก็ย้อนกลับไปอ่านกันก่อนเด้อ วันนี้เรามาเล่าวิธีการที่มัน Advance มากขึ้น อย่างการใช้ fail2ban...