3. ตัวแปรแบบ struct
ตัวแปรแบบ struct จะคล้ายๆ กับเซลล์ตรงที่ เราสามารถเก็บข้อมูลประเภทอะไรก็ได้เอาไว้ใน struct เพียงแต่ว่าการเข้าถึงข้อมูลที่อยู่ภายใน จะไม่ใช้การอ้างอิงตำแหน่งเหมือนกับอาเรย์ แต่จะอ้างอิงจากชื่อ “ฟีลด์เก็บข้อมูล” ที่อยู่ใน struct แทน
3.1 การสร้าง struct
ทำได้ 2 วิธีคือ- กำหนดค่าให้ตัวแปร struct โดยตรง
หากเราเขียนคำสั่งในรูปแบบต่อไปนี้ ตัวแปรตัวนั้นจะถูกเปลี่ยนให้เป็นประเภท struct โดยอัตโนมัติ และรูปแบบที่ว่านั้นก็คือ การใช้ . (จุด)
หากเราใช้คำสั่ง whos เพื่อตรวจสอบประเภทของตัวแปร K ก็จะได้ผลดังนี้
จะเห็นว่า Class ของตัวแปร K ถูกกำหนดให้เป็นประเภท struct โดยอัตโนมัติ
เมื่อเราเพิ่มฟีลด์เข้าไปในตัวแปร K โดยใช้ .(ชื่อฟีลด์) ตัวแปร K ก็จะกลายเป็น struct ทันที ซึ่งสามารถเพิ่มฟีลด์เข้าไปกี่ฟีลด์ก็ได้ และในฟีลด์นั้นจะเก็บค่าอะไรก็ได้
- สร้าง struct โดยใช้คำสั่ง
คำสั่งสร้าง struct มีรูปแบบดังนี้
s = struct(field1,value1,...,fieldN,valueN)
ตัวอย่างเช่น ถ้าเราจะสร้าง struct ชื่อว่า N ให้มีฟีลด์และค่าเหมือนกับ struct K ตามตัวอย่างก่อนหน้านี้ทั้งหมด เราสามารถเขียนได้เป็น
ด้วยลักษณะโครงสร้างของ struct มันจึงถูกนำไปใช้งานแบบเฉพาะเจาะจง คือ การเก็บคุณสมบัติของ object ที่เราสนใจ เช่น หากเราต้องการอ่านรูปภาพทั้งหมดที่มีอยู่ในโฟลเดอร์ เราก็จะใช้ struct เก็บชื่อ ขนาด นามสกุล และตำแหน่งที่อยู่ของรูปภาพ เอาไว้
3.2 การกำหนดค่าและการดึงข้อมูลจาก struct
จริงแล้วการกำหนดค่าให้ตัวแปร struct ก็คือวิธีแรกในหัวข้อ 3.1 นั่นแหละครับ ส่วนการดึงข้อมูลออกจาก struct ก็แค่ย้ายข้าง struct ไปไว้ด้านขวาของเครื่องหมายเท่ากับ แล้วเอาตัวแปรอะไรก็ได้มาเก็บค่าไว้ ตัวอย่างเช่น
>> ME = K.p;
เพียงแต่ว่าในการใช้งานจริง มันจะซับซ้อนกว่านั้นนิดหน่อย เราลองมาดูแผนผังโครงสร้างนี้นะครับ จะได้เข้าใจง่ายๆ
จากแผนภาพด้านบน เราจะเห็นว่าตัวแปร struct ไม่จำเป็นต้องมีข้อมูลชุดเดียว ยกตัวอย่างเช่น ถ้า struct N คือ นักเรียน ในโรงเรียนก็ไม่จำเป็นต้องมีนักเรียนคนเดียว ดังนั้นจึงมี struct N ตัวที่ 1, 2, 3 ไปเรื่อยๆ ซึ่งก็เปรียบเสมือนกับนักเรียนคนที่ 1, 2, 3 นั่นแหละครับ แต่ไม่ว่าจะมีนักเรียนกี่คน นักเรียนทุกคนก็จะมีข้อมูลเหมือนกันเสมอ คือ เพศ ชื่อ และ รหัส ซึ่งข้อมูลเหล่านี้จะถูกนำมาทำเป็นฟีลด์ให้ struct
สมมุติว่า เพศ ชื่อ รหัส คือฟีลด์ A, B, C ตามลำดับ ถ้าเราอยากได้ชื่อของนักเรียนคนที่ 2 เราก็ต้องเขียนโค้ดดังนี้
>> name = N(2).B;
ตัวแปร name คือตัวแปรที่เราเอามาไว้เก็บชื่อ ส่วนด้านขวามือของเครื่องหมายเท่ากับหมายความว่า ให้ดึงข้อมูลจาก struct N ตำแหน่งที่ 2 ฟีลด์ B
เพื่อให้เข้าใจมากขึ้น เรามาลองทำตัวอย่างกันเลยครับ
ก่อนอื่นให้ทุกคนสร้างโฟลเดอร์ใหม่ขึ้นมา แล้วหารูปภาพอะไรก็ได้มาไว้ในโฟลเดอร์นี้สัก 10 รูป จากนั้นสร้าง m-file ขึ้นมา แล้วบันทึกไว้ในโฟลเดอร์เดียวกันกับรูปภาพทั้ง 10 รูป โดยตั้งชื่อว่า Example10.m
หลังจากนั้นก็เปลี่ยน current folder ของ MATLAB มาที่โฟลเดอร์นี้ ซึ่งจะได้หน้าตาประมาณนี้
ตัวอย่างต่อไปนี้ เราจะทำการอ่านข้อมูลทั้งหมดของภาพที่อยู่ในโฟลเดอร์นี้มาเก็บไว้ในตัวแปร struct นะครับ โดยรูปภาพแต่ละรูปจะมีฟีลด์ข้อมูลดังนี้ ชื่อ ประเภท ขนาด ตำแหน่ง (จริงๆ แล้ว MATLAB มีคำสั่งอ่านภาพทั้งโฟลเดอร์อยู่แล้วนะครับ แต่ในตัวอย่างนี้ผมจะเขียนให้ดูทีละขั้นตอน เพื่อให้เห็นการเก็บข้อมูลเข้า struct และการดึงข้อมูลออกจาก struct)
clc;clear;close all; % Create struct picdata = struct('name',[],'type',[],'size',[],'location',[]); % 1. Read jpg image N1 = dir('*.jpg'); L1 = length(N1); k = 1; for m=1:L1 name = N1(m).name; tx = regexp(name,'\.','split'); type = tx{2}; pic = imread(name); [r,c,l] = size(pic); loc = fullfile(pwd,name); picdata(k).name = name; picdata(k).type = type; picdata(k).size = [r,c]; picdata(k).location = loc; k = k+1; end % 2. Read png image N2 = dir('*.png'); L2 = length(N2); for m=1:L2 name = N2(m).name; tx = regexp(name,'\.','split'); type = tx{2}; pic = imread(name); [r,c,l] = size(pic); loc = fullfile(pwd,name); picdata(k).name = name; picdata(k).type = type; picdata(k).size = [r,c]; picdata(k).location = loc; k = k+1; end
เมื่อรันโปรแกรมข้างต้น จะไม่มีผลลัพธ์ใดๆ แสดงออกมา เพราะเราไม่ได้สั่งแสดงผล แต่เราจะสังเกตุเห็นว่าใน workspace จะมีตัวแปรชื่อว่า picdata อยู่ และเมื่อเราดูข้อมูลในตัวแปร picdata ก็จะเห็นฟีลด์ต่างๆ ตามที่เราได้ออกแบบเอาไว้
ในตัวอย่างนี้เราจะเห็นคำสั่งพิเศษอยู่ 3 คำสั่งนะครับ ได้แก่
1. คำสั่ง dir
คำสั่งนี้ใช้ค้นหาไฟล์ทั้งหมดที่อยู่ในโฟลเดอร์ที่เรากำหนดครับ ซึ่งผลลัพธ์ที่ได้ก็จะอยู่ในรูปแบบ struct เช่นกัน ดังนั้นจึงจะเห็นว่า N1 ที่ผมใช้เก็บค่าจากคำสั่ง dir เวลาจะดึงค่าออกมา ก็ต้องดึงแบบ struct ด้วย ตัวอย่างเช่น บรรทัดที่ 11 ที่ผมดึงชื่อไฟล์ออกมาจากตัวแปร N1
2. คำสั่ง regexp
คำสั่งนี้ใช้งานได้หลากหลายครับ รายละเอียดดูใน help ได้เลย แต่ในตัวอย่างนี้ ผมใช้คำสั่งนี้เพื่อแยกกลุ่มตัวอักษร ซึ่งกลุ่มตัวอักษรที่ว่าก็คือ ชื่อของรูปภาพนั้นเอง เช่น 01.jpg ซึ่งเราจะเห็นว่าประเภทของภาพ หรือ นามสกุลของภาพ จะอยู่ด้านหลัง . เสมอ ดังนั้นผมจึงใช้คำสั่ง regexp ในโหมด split เพื่อแยกตัวอักษรที่อยู่หน้า . และหลังออกจากกัน ผลลัพธ์ที่ได้จะเป็นชนิด cell และประเภทของรูปภาพจะอยู่ในตำแหน่งที่ 2 ดังนั้นในบรรทัดที่ 13 ผมจึงต้องดึงข้อมูลด้วยการใช้ { } เพราะ tx เป็นตัวแปรประเภทเซลล์ นั่นเองครับ
3. คำสั่ง fullfile
คำสั่งนี้เป็นคำสั่งรวมชื่อไฟล์ และตำแหน่งของไฟล์เข้าด้วยกัน โดยที่ pwd คือคำสั่งที่แสดงตำแหน่งปัจจุบันของ current folder ซึ่งผลลัพธ์ที่ได้จะเป็นชื่อไฟล์ในรูปแบบเต็ม ซึ่งหากเราเรียกไฟล์ใดก็ตามในชื่อรูปแบบเต็ม ไม่ว่าไฟล์นั้นจะอยู่ที่ไหนก็ตาม ก็จะเรียกได้เสมอ หรือก็คือ ถึงแม้ไฟล์นั้นจะไม่ได้อยู่ใน current folder ก็ยังเรียกไฟล์นั้นได้
ในตัวอย่างนี้เราจะเห็นคำสั่งพิเศษอยู่ 3 คำสั่งนะครับ ได้แก่
1. คำสั่ง dir
คำสั่งนี้ใช้ค้นหาไฟล์ทั้งหมดที่อยู่ในโฟลเดอร์ที่เรากำหนดครับ ซึ่งผลลัพธ์ที่ได้ก็จะอยู่ในรูปแบบ struct เช่นกัน ดังนั้นจึงจะเห็นว่า N1 ที่ผมใช้เก็บค่าจากคำสั่ง dir เวลาจะดึงค่าออกมา ก็ต้องดึงแบบ struct ด้วย ตัวอย่างเช่น บรรทัดที่ 11 ที่ผมดึงชื่อไฟล์ออกมาจากตัวแปร N1
2. คำสั่ง regexp
คำสั่งนี้ใช้งานได้หลากหลายครับ รายละเอียดดูใน help ได้เลย แต่ในตัวอย่างนี้ ผมใช้คำสั่งนี้เพื่อแยกกลุ่มตัวอักษร ซึ่งกลุ่มตัวอักษรที่ว่าก็คือ ชื่อของรูปภาพนั้นเอง เช่น 01.jpg ซึ่งเราจะเห็นว่าประเภทของภาพ หรือ นามสกุลของภาพ จะอยู่ด้านหลัง . เสมอ ดังนั้นผมจึงใช้คำสั่ง regexp ในโหมด split เพื่อแยกตัวอักษรที่อยู่หน้า . และหลังออกจากกัน ผลลัพธ์ที่ได้จะเป็นชนิด cell และประเภทของรูปภาพจะอยู่ในตำแหน่งที่ 2 ดังนั้นในบรรทัดที่ 13 ผมจึงต้องดึงข้อมูลด้วยการใช้ { } เพราะ tx เป็นตัวแปรประเภทเซลล์ นั่นเองครับ
3. คำสั่ง fullfile
คำสั่งนี้เป็นคำสั่งรวมชื่อไฟล์ และตำแหน่งของไฟล์เข้าด้วยกัน โดยที่ pwd คือคำสั่งที่แสดงตำแหน่งปัจจุบันของ current folder ซึ่งผลลัพธ์ที่ได้จะเป็นชื่อไฟล์ในรูปแบบเต็ม ซึ่งหากเราเรียกไฟล์ใดก็ตามในชื่อรูปแบบเต็ม ไม่ว่าไฟล์นั้นจะอยู่ที่ไหนก็ตาม ก็จะเรียกได้เสมอ หรือก็คือ ถึงแม้ไฟล์นั้นจะไม่ได้อยู่ใน current folder ก็ยังเรียกไฟล์นั้นได้
จบหัวข้อที่ 3