หลังจากที่ทำความรู้จักกับภาษา Clojure ไปบ้างเล็กน้อยแล้ว
ต่อมาก็เริ่มไปดู Data structure พื้นฐาน
ทั้ง Vector, List, Map, Keyword และ Set
โดยครั้งนี้จะเรียนรู้กับ Vector และ List กัน
มาเริ่มกันเลย
Vector เป็น data structure ที่ใช้เยอะมาก ๆ ในภาษา Clojure
ซึ่งในแต่ละ item นั้นมีชนิดที่แตกต่างกันได้ รวมทั้งสามารถมี Vector ซ้อน Vector ได้แบบสบาย ๆ โดยที่รูปแบบ syntax ของ Vector นั้น จะอยู่ในเครื่องหมายก้ามปู [] แต่ละ item คั่นด้วยช่องว่าง (space bar) สามารถใส่ comma (,) ได้นะ แต่ตัว compiler จะ ignore ไปเอง มาดู code ตัวอย่างกัน [gist id="8f6fd3d70a858cc0f3db0cec3178e738" file="1.txt"] แต่ตัวภาษาก็มี function ชื่อว่า vector มาใช้สำหรับสร้าง Vector ให้ด้วย ซึ่งน่าจะช่วยเพิ่มทางเลือกให้ใช้งานอีกด้วย แต่ส่วนใหญ่จะใช้แบบแรกกันนะ [gist id="8f6fd3d70a858cc0f3db0cec3178e738" file="2.txt"] มาดู function อื่น ๆ สำหรับทำงานกับ Vector กันบ้าง- count สำหรับนำจำนวน item ใน Vector
- first สำหรับดึงค่าในตำแหน่งแรกของ Vector
- rest จะแสดงข้อมูลตั้งแต่ในลำดับที่สองเป็นต้นไป แต่ return ออกมาไม่ใช่ Vector นะ แต่มันคือ sequence ?
Sequence มันคืออะไร ? ชีวิตยากอะแล้ว พักไว้ก่อนมาดูตัวอย่างการใช้งาน [gist id="8f6fd3d70a858cc0f3db0cec3178e738" file="3.txt"] ถ้าต้องการเข้าถึงข้อมูลแต่ละตำแหน่งละ ? ในภาษา Clojure จะมี function ชื่อว่า nth ให้ใช้งาน โดยจะเริ่มตำแน่งที่ 0 ของ Vector ใช้งานดังนี้ [gist id="8f6fd3d70a858cc0f3db0cec3178e738" file="4.txt"] nth มันคืออะไรนะ ? ชื่อมันแปลกดี ไม่เคยพบเห็นมาก่อน ดังนั้นจึงลองไปค้นหาดู พบว่ามันคือ คำที่มีความหมายทางคณิตศาสตร์ ดังนี้ [code] nth enTH/Submit adjective MATHEMATICS denoting an unspecified member of a series of numbers or enumerated items. "systematic sampling by taking every nth name from the list" [/code] ถ้าต้องการเพิ่มข้อมูลเข้าไปยัง Vector ทำอย่างไร ? จะใช้ function ชื่อว่า conj ซึ่งย่อมาจาก conjunction หรือการเชื่อมต่อหรือเชื่อมโยง ซึ่งจะทำการเพิ่มข้อมูลไปยังตำแหน่งสุดท้ายของ Vector แต่ถ้าต้องการเพิ่มข้อมูลไปยังตำแหน่งแรกสุดของ Vector สามารถใช้ function cons ซึ่งย่อมาจาก construct มาดูตัวอย่างการใช้งาน [gist id="8f6fd3d70a858cc0f3db0cec3178e738" file="5.txt"] สิ่งที่แตกต่างระหว่าง conj และ cons คือ cons จะทำการ return ข้อมูลเป็นชนิด sequence อีกแล้วนะ !!
ปล. สิ่งที่ควรจำไว้คือ ทุก ๆ function ที่กระทำกับ Vector นั้น จะไม่ไปแก้ไขหรือเปลี่ยนแปลง Vector ต้นฉบับเลย เพียงแค่ return value กลับมาเท่านั้น ซึ่งเป็นพื้นฐานของภาษา Clojure นั่นคือ immutability
มาดู List กันบ้าง ว่าเป็นอย่างไร ?
มันเหมือนกับ Vector มาก ๆ แต่การใช้งานมีรูปแบบที่ต่างกัน มาดูการสร้าง List กัน โดยใช้เครื่องหมายวงเล็บ และ execute list ด้วยเครื่องหมาย single qoute (‘) หรือใช้ function ชื่อ list ก็ได้ ส่วน function อื่น ๆ ใช้เหมือน Vector เลยครับ ไม่ต้อมาจำให้วุ่นวายแต่สิ่งที่ต่างคือ function conj และ cons ให้ผลเหมือนกัน !! คือเป็นการเพิ่มไปยังตำแหน่งแรกของ Listดังนี้ [gist id="8f6fd3d70a858cc0f3db0cec3178e738" file="6.txt"]
มีคำถามว่า ทำไมต้องมีทั้ง Vector และ List ด้วยละ ทั้ง ๆ ที่เหมือนกันมาก ๆ ?
สิ่งที่ Clojure อธิบายไว้อย่างน่าสนใจคือ มองจากภายนอกนั้นจะเหมือนกันมาก (External) แต่เมื่อดูการทำงานภายในแล้วต่างกัน (Internal) โดยที่ Vector นั้นมองเหมือนกับ array ข้อมูลแต่ละตำแหน่งอยู่ในหน่วยความจำที่ต่อเนื่องกันดังรูป แต่ List จะตรงข้ามกับ Vector เลย เพราะว่าคือ Linked List แสดงดังรูป ส่งผลให้การเข้าถึงข้อมูลในแต่ละตำแหน่งต่างกัน โดยการเข้าถึงของ Vector จะเร็วกว่า List เพราะว่าใช้การคำนวณทางคณิตศาสตร์ ส่วน List ต้องไปตามลำดับที่ link กันไว้ แต่การใช้งานต้อดู use case ด้วยว่าอะไรที่เหมาะกับ Vector หรือ Listสิ่งที่ Clojure ให้ความสำคัญมาก ๆ ของ data structure ต่าง ๆ คือ เรื่องของ performance ในการทำงานซึ่งในโลกของ Clojure นั้น จะมีการใช้งาน Vector มากกว่า List มาก ปล. การทำงานภายในของ Vector และ List น่าสนใจมาก มีทั้งเรื่องของ caching และ การจัดการ memory ซึ่งไว้ต้องศึกษาเพิ่มเติมอีก