อาเรย์ ในภาษา Ruby
ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับอาเรย์ในภาษา Ruby เราจะพูดเกี่ยวกับการประกาศและใช้งานอาเรย์ และการใช้งานเมธอดที่สำคัญของอาเรย์เพื่อใช้จัดการข้อมูลในอาเรย์ และก่อนที่จะเริ่ม มาทำความรู้จักกันก่อนว่าอาเรย์คืออะไร
อาเรย์ (Array) คือข้อมูลแบบชุดลำดับที่สามารถเก็บค่าได้หลายค่าในตัวแปรเดียว อาเรย์มี index ที่ใช้สำหรับอ้างถึงข้อมูลในตัวแปรอาเรย์ นั่นทำให้เราสามารถจัดการกับค่าในอาเรย์ได้เหมือนกับว่ามันเป็นตัวแปรปกติ อาเรย์นั้นเป็นออบเจ็คจากคลาส Array
ซึ่งมีเมธอดต่างๆ เป็นจำนวนมากสำหรับทำงานกับอาเรย์
การประกาศอาเรย์
วิธีที่ง่ายที่สุดในการประกาศอาเรย์คือการใช้อาเรย์ Literal นี่เป็นรูปแบบการประกาศอาเรย์ในภาษา Ruby
array_name = [object1, object2, object3, ...]
โดยที่ name
นั้นเป็นชื่อของตัวแปรอาเรย์ และหลังจากนั้นเป็นการกำหนดค่าให้กับอาเรย์ โดยสมาชิกของอาเรย์จะต้องอยู่ในเครื่องหมายวงเล็บ [ ... ]
และคั่นสมาชิกแต่ละตัวด้วยเครื่องหมายคอมมา (,
) นี่เป็นตัวอย่างของการประกาศอาเรย์ในภาษา Ruby
numbers = [10, 20, 30, 40, 50]
fruits = ["Apple", "Lemon", "Orange"]
basket = []
ในตัวอย่าง เราได้ประกาศตัวแปรอาเรย์มาสามตัว ซึ่งแต่ละตัวนั้นเก็บข้อมูลที่แตกต่างกัน ตัวแปรอาเรย์ numbers
นั้นเก็บตัวเลขจำนวนเต็ม 5 ตัว ดังนั้นเราสามารถกล่าวได้ว่าอาเรย์นี้มีสมาชิก 5 ตัว ส่วนตัวแปรอาเรย์ fruits
นั้นเก็บค่าที่เป็น String จำนวน 3 ตัว
สุดท้ายตัวแปรอาเรย์ basket
ในตัวแปรนี้เราไม่ได้กำหนดสมาชิกใดๆ ให้กับมันเลย ดังนั้นจึงถือว่ามันเป็นอาเรย์ว่างหรือไม่มีสมาชิก ซึ่งในทางปฏิบัติ เราอาจจะประกาศอาเรย์ว่างและกำหนดค่าให้มันในภายหลังได้
หลังจากที่ประกาศอาเรย์ไปแล้ว คุณสามารถใส่ออบเจ็คเข้าไปเพิ่มในอาเรย์ได้ โดยการใช้เมธอด push
หรือเครื่องหมาย <<
ซึ่งทั้งสองรูปแบบมีความหมายเหมือนกัน เมื่อเราได้เพิ่มข้อมูลเข้าไปในอาเรย์ ข้อมูลจะไปเข้าต่อท้ายสมาชิกสุดท้ายของอาเรย์
scores = [10, 20, 30]
scores.push(40)
scores.push(50)
scores << 60
p scores # => [10, 20, 30, 40, 50, 60]
เนื่องจาก Ruby นั้นมีประเภทข้อมูลเป็นแบบไดนามิกส์ นั่นทำให้เราสามารถเก็บออบเจ็คประเภทที่แตกต่างกันในอาเรย์ได้ ตัวแปรอาเรย์ stuff
ของเราได้เก็บตัวเลขจำนวนเต็ม เลขทศนิยม ข้อความ และออบเจ็คของเวลา อย่างไรก็ตาม ในการเขียนโปรแกรมส่วนมากแล้วเรามักจะใช้อาเรย์เก็บข้อมูลประเภทเดียวกัน ยกเว้นแต่ว่าคุณต้องการทำบางอย่างที่นอกเหนือจากนั้น
stuff = [1, 3.14, "Ruby", Time.now]
p stuff # => [1, 3.14, "Ruby", 2020-01-19 03:12:45 +0700]
หลังจากที่ได้ประกาศอาเรย์ไปแล้ว ในบางครั้งเราก็อาจจะอยากทราบว่าอาเรย์นั้นมีสมาชิกจำนวนเท่าไร ต่อไปมาดูตัวอย่างสำหรับนับจำนวนสมาชิกภายในอาเรย์กัน
names = ["Meteo", "Luke", "Samuel"]
puts "Initialize array with three names"
puts names.length
names.push("Narcissus")
names.push("Ramsey")
puts "Pushed two names to the array"
puts names.length
นี่เป็นผลลัพธ์ของโปรแกรม
Initialize array with three names
3
Pushed two names to the array
5
ในตัวอย่างนั้นแสดงให้เห็นว่าเราสามารถใช้เมธอด length
เพื่อนับจำนวนสมาชิกในอาเรย์ได้ เราได้ประกาศตัวแปรอาเรย์ names
และเก็บชื่อจำนวนสามชื่อในตอนแรก และแน่นอนเมื่อเราเรียกใช้เมธอด length
จำนวนวสมาชิกของอาเรย์นั้นมีค่าเป็น 3
หลังจากนั้นเราใส่อีกสองชื่อเข้าไปในอาเรย์ด้วยเมธอด push
และตอนนี้อาเรย์มีสมาชิกทั้งหมด 5
ตัว
เทคนิค: เรามักจะใช้เมธอด
p
เพื่อดูข้อมูลในตัวแปรอาเรย์ ซึ่งมันเป็นวิธีที่ง่ายต่อการตรวจสอบข้อมูลที่ถูกเก็บในตัวแปรอาเรย์
การเข้าถึงและอ่านค่าในอาเรย์
ในการเข้าถึงสมาชิกภายในอาเรย์ โดยทั่วไปแล้วเราจะต้องทำผ่าน index ซึ่ง index ของอาเรย์นั้นเป็นตัวเลขจำนวนเต็มที่เริ่มจาก 0
ถึง n - 1
เมื่อ n
เป็นจำนวนสมาชิกทั้งหมดของอาเรย์
numbers = [10, 20, 30, 40, 50]
puts numbers[0]
puts numbers[1]
puts numbers[4]
นี่เป็นผลลัพธ์ของโปรแกรม
10
20
50
ในตัวแปรอาเรย์ numbers
นั้นมีสมาชิกทั้งหมดจำนวน 5 ตัว นั่นหมายความว่า index ของอาเรย์จะมีค่าตั้งแต่ 0 - 4
ดังนั้นการเข้าถึงค่าต่างๆ ภายในอาเรย์สามารถเขียนได้เป็น numbers[index]
ดังนั้น numbers[0]
เป็นการเข้าถึงสมาชิกตัวแรกในอาเรย์ numbers[1]
เป็นการเข้าถึงสมาชิกตัวที่สอง ไปตามลำดับจนถึงสมาชิกตัวสุดท้าย ที่สามารถเข้าถึงได้โดย numbers[4]
นอกจากการอ่านค่าแล้ว เราสามารถเข้าถึงสมาชิกในอาเรย์เพื่อเปลี่ยนแปลงค่าได้เช่นเดียวกัน ดังในตัวอย่างต่อไปนี้
numbers = [10, 20, 30, 40, 50]
p numbers
numbers[0] = 15
numbers[2] = 35
numbers[4] = numbers[4] * 2
p numbers
นี่เป็นผลลัพธ์ของโปรแกรม
[10, 20, 30, 40, 50]
[15, 20, 35, 40, 100]
ในตัวอย่าง เราได้เปลี่ยนค่าสมาชิกตัวแรกและตัวที่สามในอาเรย์เป็น 15
และ 35
ตามลำดับ หลังจากนั้นเปลี่ยนค่าสมาชิกตัวสุดท้ายให้มีค่าเพิ่มขึ้นเป็นสองเท่า
ในตัวอย่างก่อนหน้าเป็นการเข้าถึงสมาชิกในอาเรย์ด้วย index ที่เป็นจำนวนเต็มบวก ในภาษา Ruby คุณสามารถเข้าถึงสมาชิกในอาเรย์ด้วย index ที่เป็นจำนวนเต็มลบได้ มาดูตัวอย่าง
fruits = ["Apple", "Lemon", "Orange", "Banana", "Pear"]
puts fruits[-1]
puts fruits[-2]
puts fruits[-5]
fruits[-5] = "Mango"
puts fruits[-5]
นี่เป็นผลลัพธ์ของโปรแกรม
Pear
Banana
Apple
Mango
คุณสามารถระบุ index ที่มีค่าเป็นลบเพื่อเข้าถึงสมาชิกในอาเรย์ได้ โดยที่ -1
เป็นการเข้าถึงสมาชิกชิกตัวสุดท้ายในอาเรย์ และ -2
เป็นสมาชิกรองสุดท้ายในอาเรย์ถัดมาเรื่อยๆ ในตัวอย่างเราได้ใช้ index ที่เป็นจำนวนเต็มลบกับอาเรย์ fruits
และมันก็ทำงานได้ดี ซึ่งวิธีนี้อาจจะเป็นประโยชน์ได้ในกรณีที่เราต้องการเข้าถึงสมาชิกในอาเรย์โดยอ้างอิงจากตัวสุดท้าย ยกตัวอย่างเช่น
scores = [95, 82, 70, 63, 59, 50]
puts "Third lowest score: #{scores[-3]}"
เราต้องการทราบว่าคะแนนที่น้อยที่สุดเป็นอันดับที่สามในอาเรย์คืออะไร เราสามารถใช้ index ที่เป็นลบเพื่อเข้าถึงสมาชิกในตำแหน่งที่สามจากท้ายของอาเรย์ได้โดยไม่ต้องสนใจว่าขนาดของอาเรย์จะเป็นเท่าไหร่ อย่างไรก็ตาม จากตัวอย่างนั้นข้อมูลในอาเรย์ต้องเรียงจากมากไปน้อยแล้วเท่านั้น
การใช้คำสั่งวนซ้ำกับอาเรย์
อาเรย์นั้นเก็บข้อมูลเป็นแบบลำดับและข้อมูลเหล่านั้นสามารถเข้าถึงได้โดย index ของมัน นั้นจึงเป็นเรื่องที่สะดวกที่เราจะใช้คำสั่งวนซ้ำอย่างเช่น คำสั่ง for
เพื่อวนอ่านค่าในตัวแปรอาเรย์ผ่านทาง index ของมัน นี่เป็นตัวอย่าง
names = ["Meteo", "Luke", "Samuel", "Narcissus", "Ramsey"]
for i in (0...names.length)
puts names[i]
end
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Meteo
Luke
Samuel
Narcissus
Ramsey
ในตัวอย่าง เราได้ใช้คำสั่งวนซ้ำ for เพื่อวนอ่านค่าในตัวแปรอาเรย์ โดยการสร้าง index จากออบเจ็ค Range ซึ่ง index ของเราจะเริ่มจาก 0 ถึงขนาดของอาเรย์ names.length - 1
ซึ่งสามารถแสดงได้ด้วยออบเจ็ค (0...names.length)
ในแต่ละรอบของการวนซ้ำ เราได้จะได้รับค่า index มาเก็บไว้ในตัวแปร i
นั่นจึงทำให้เราสามารถนำ index ที่ได้ไปใช้กับตัวแปรอาเรย์เพื่ออานข้อมูลออกมาแสดงผลได้
มันขึ้นอยู่กับคุณว่าจะประยุกต์ใช้งานคำสั่งวนซ้ำจากอาเรย์อย่างไร จากในตัวอย่างก่อนหน้า เราสามารถแก้ไขโค้ดเพื่อให้โปรแกรมอ่านข้อมูลเริ่มจากสมาชิกตัวสุดท้ายของอาเรย์ได้
# Reading array in reverse order
# Method 1
names = ["Meteo", "Luke", "Samuel", "Narcissus", "Ramsey"]
for i in (0...names.length)
puts names[(i + 1) * -1]
end
# Method 2
names = ["Meteo", "Luke", "Samuel", "Narcissus", "Ramsey"]
for i in (0...names.length)
puts names[names.length - 1 - i]
end
จากทั้งสองตัวอย่างนั้นให้ผลลัพธ์ที่เหมือนกัน ตัวอย่างแรกเป็นการเข้าถึงสมาชิกในอาเรย์ด้วย index ที่เป็นลบ names[(i + 1) * -1]
และตัวอย่างที่สองเป็นการสร้าง index แบบผันกลับด้วยการคำนวณจากขนาดของอาเรย์ names[names.length - 1 - i]
ต่อไปมาดูตัวอย่างการใช้งานคำสั่งวนซ้ำกับอาเรย์ เราจะเขียนโปรแกรมเพื่อหาจำนวนประกอบทั้งหมดของตัวเลขจำนวนเต็มที่รับเข้ามาจากคีย์บอร์ด
print "Enter number: "
n = gets.chomp.to_i
factors = []
for i in (1..n)
factors.push(i) if n % i == 0
end
puts "There are #{factors.length} factors of #{n}:"
p factors
นี่เป็นผลลัพธ์ของโปรแกรม เมื่อเรากรอกค่าเป็น 78
Enter number: 78
There are 8 factors of 78:
[1, 2, 3, 6, 13, 26, 39, 78]
และนี่เป็นอีกผลลัพธ์ เมื่อเรากรอกค่าเป็น 245
Enter number: 245
There are 6 factors of 245:
[1, 5, 7, 35, 49, 245]
ในตัวอย่าง แสดงให้เห็นว่าเราสามารถใช้อาเรย์เพื่อเก็บค่าที่ได้จากการทำงานบางอย่างได้ โปรแกรมของเรารับค่า n
เข้ามาทางคีย์บอร์ด และเพื่อหาตัวประกอบทั้งหมดของจำนวนเต็ม n
เราต้องการหาว่าตั้งแต่ 1 - n
นั้นมีตัวเลขไหนบ้างที่หาร n
และถ้าหากว่าตัวเลขใดๆ หาร n
ลงตัว มันถือว่าเป็นตัวประกอบของ n
factors.push(i) if n % i == 0
ในคำสั่งนี้เป็นการตรวจสอบว่าตัวเลขนั้นหาร n
ลงตัวหรือไม่ และถ้าหากหารลงตัวเราใส่ตัวเลขดังกล่าวลงไปในตัวแปรอาเรย์ factors
ของเรา สังเกตว่าในตอนแรกเราได้ประกาศให้มันเป็นอาเรย์ว่างก่อน เพื่อที่เราจะได้ใส่ค่าลงไปในภายหลังได้
ข้อควรรู้: ในตัวอย่างสังเกตว่าเราใช้ Range อยู่สองแบบคือแบบสามจุด
(0...n)
และแบบสองจุด(0..n)
แบบแรกนั้นเป็นการสร้างลำดับตัวเลขที่ไม่รวมn
ในขณะที่แบบที่สองจะรวมn
ด้วย ดังนั้นเมื่อใช้ Range เพื่อสร้าง index ของอาเรย์ เรามักจะใช้แบบสามจุด เนื่องจากว่าสมาชิกตัวสุดท้ายในอาเรย์นั้นมี index เท่ากับn - 1
เมื่อn
เป็นขนาดของอาเรย์
การวนรอบอาเรย์
ในตัวอย่างก่อนหน้า เราได้ใช้คำสั่งวนซ้ำ for เพื่อที่จะวนอ่านค่าในอาเรย์ ซึ่งในความเป็นจริงแล้ว Ruby ได้มีเมธอด each ที่เราสามารถใช้วนอ่านค่าในอาเรย์ได้เลย มาดูตัวอย่าง
names = ["Meteo", "Luke", "Samuel", "Narcissus", "Ramsey"]
names.each { |item|
puts "#{item} #{item.length}"
}
นี่เป็นผลลัพธ์ของโปรแกรม เราได้แสดงชื่อในอาเรย์ออกมาและดูว่าแต่ละชื่อนั้นมีความยาวเท่าไหร่
Meteo 5
Luke 4
Samuel 6
Narcissus 9
Ramsey 6
ในตัวอย่าง เราได้ใช้เมธอด each
ในการวนอ่านค่าในอาเรย์ เมธอดนี้รับบล็อคเป็นอาร์กิวเมนต์ นั่นหมายความว่าในแต่ละรอบของการวนในอาเรย์ โปรแกรมจะเรียกใช้งานบล็อคนี้ โดยส่งค่าสมาชิกในอาเรย์แต่ละตัวผ่านเข้ามาทางตัวแปร item
ที่เราได้ประกาศไว้ในบล็อค
และถ้าหากคุณต้องการวนอ่านค่ามาจากสมาชิกตัวสุดท้ายของอาเรย์ คุณสามารถใช้เมธอด reverse_each
เพื่อการทำงานนี้ได้
names = ["Meteo", "Luke", "Samuel", "Narcissus", "Ramsey"]
names.reverse_each { |item|
puts "#{item} #{item.length}"
}
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Ramsey 6
Narcissus 9
Samuel 6
Luke 4
Meteo 5
ในบางกรณี เราอาจจะจำเป็นต้องนำ index ของอาเรย์มาใช้งานบางอย่าง ยกตัวอย่างเช่น เราต้องการสร้าง ID ของภาษาเขียนโปรแกรมด้วย index ของมันก่อนที่จะจัดเก็บไว้ในฐานข้อมูล หรือนำมาแสดงผล ซึ่งเราสามารถวนรอบ index ของอาเรย์ได้ด้วยเมธอด each_index
lang = ["Ruby", "PHP", "Python", "Perl"]
puts "ID\tLanguage"
lang.each_index { |i|
puts "#{i + 1}\t#{lang[i]}"
}
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
ID Language
1 Ruby
2 PHP
3 Python
4 Perl
ในตัวอย่าง เราได้สร้าง ID ของแต่ละภาษาเขียนโปรแกรมด้วย index ของมัน และเนื่องจากว่าเมธอด each_index
นั้นส่งเพียงค่า index เข้ามาในบล็อคเท่านั้น ในกรณีที่เราจะเข้าถึงค่าในอาเรย์ เราสามารถเข้าถึงค่าในรอบปัจจุบันได้ด้วยคำสั่ง lang[i]
สังเกตว่าการใช้งานเมธอด each_index
นั้นมีความคล้ายคลึงกับการใช้คำสั่งวนซ้ำ for เพื่อวนอ่านค่าในอาเรย์มาก และแน่นอนว่าทั้งสองวิธีให้ผลลัพธ์ที่เหมือนกัน
อาเรย์ซ้อนอาเรย์
อาเรย์นั้นเป็นออบเจ็คที่สามารถเก็บข้อมูลได้ทุกประเภทในตัวมัน และแน่นอนว่าเราสามารถเก็บอาเรย์ไว้ในอาเรย์ได้ ซึ่งการทำเช่นนี้จะทำให้เกิดอาเรย์ซ้อนอาเรย์ หรืออาเรย์หลายมิติ (Multi-dimensional array) ขึ้นได้ ในบทนี้ เราจะพูดถึงอาเรย์ที่ซ้อนกันเพียงสองชั้นเท่านั้น
ลองจินตนาการว่า เราต้องการเขียนโปรแกรมที่เก็บคะแนนของนักเรียน 3 คน ซึ่งแต่ละคนนั้นจะมีคะแนนของ 4 วิชาที่เราจะต้องเก็บ นั่นหมายความว่าเราต้องการเก็บคะแนนทั้งหมด 12 ค่า ซึ่งโจทย์ปัญหานี้สามารถแก้ได้ด้วยการเก็บด้วยอาเรย์ซ้อนอาเรย์ โดยการทำเช่นนี้จะทำให้เราสามารถเก็บคะแนนทั้งหมดไว้ได้เพียงในตัวแปรอาเรย์ตัวแปรเดียว
นี่เป็นวิธีที่เราเก็บข้อมูลดังกล่าวในตัวแปรอาเรย์ซ้อนอาเรย์ในภาษ Ruby
scores = [
[67, 45, 58, 75],
[71, 38, 73, 91],
[35, 32, 57, 89]
]
ในแต่ละแถวของอาเรย์ (แนวนอน) จะเป็นคะแนนของนักเรียนแต่ละคน ในขณะที่แต่ละหลักของอาเรย์ (แนวตั้ง) จะเป็นคะแนนของแต่ละวิชาที่นักเรียนสอบได้ ต่อไปเราจะวนอ่านค่าในตัวแปรอาเรย์ทั้งหมดออกมา
scores = [
[67, 45, 58, 75],
[71, 38, 73, 91],
[35, 32, 57, 89]
]
for i in(0...scores.length)
for j in (0...scores[i].length)
print "#{scores[i][j]} "
end
puts
end
นี่เป็นผลลัพธ์ของโปรแกรม
67 45 58 75
71 38 73 91
35 32 57 89
ในตัวอย่าง เป็นการวนอ่านค่าอาเรย์ซ้อนอาเรย์ด้วยคำสั่งวนซ้ำ for สังเกตว่าเราจะต้องใช้คำสั่ง for ซ้อนกันเพื่อวนอ่านค่าในอาเรย์ที่ซ้อนกัน
for i in(0...scores.length)
ในคำสั่ง for รอบนอกนั้น เป็นการวนอ่านค่าของอาเรย์ในแต่ละแถว ดังนั้นเราสามารถเข้าถึงค่าในแต่ละแถวได้ด้วยคำสั่ง scores[i]
for j in (0...scores[i].length)
ต่อมาเราได้สร้างคำสั่ง for เพื่อวนอ่านค่าสมาชิกของอาเรย์ในแต่ละแถว และเข้าถึงสมาชิกในอาเรย์โดยอ้างอิงจากอาเรย์หลักได้ด้วยคำสั่ง scores[i][j]
จากตัวอย่างก่อนหน้า เนื่องจากเราทราบว่าเราเก็บข้อมูลของนักเรียนสามคน และเก็บทั้งหมดเป็นจำนวน 4 วิชา ดังนั้นเราสามารถจัดรูปแบบการแสดงผลใหม่เพื่อให้เราใจได้มากขึ้น เป็นดังนี้
names = ["Meteo", "Luke", "Sofia"]
subjects = ["Math", "Science", "Art", "History"]
scores = [
[67, 45, 58, 75],
[71, 38, 73, 91],
[35, 32, 57, 89]
]
puts subjects.join("\t")
for i in(0...scores.length)
for j in (0...scores[i].length)
print "#{scores[i][j]}\t"
end
puts "#{names[i]}"
end
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Math Science Art History
67 45 58 75 Meteo
71 38 73 91 Luke
35 32 57 89 Sofia
สังเกตว่าผลลัพธ์ของโปรแกรมจะสอดคล้องกับที่เราได้บอกไปในตอนแรกว่า ในแต่ละแถวของอาเรย์ (แนวนอน) จะเป็นคะแนนของนักเรียนแต่ละคน ในขณะที่ในแต่ละหลักของอาเรย์ (แนวตั้ง) จะเป็นคะแนนของแต่ละวิชาที่นักเรียนสอบได้
ในบทนี้ คุณได้เรียนรู้เกี่ยวการสร้างและการใช้งานอาเรย์ในภาษา Ruby รวมถึงการเข้าถึงสมาชิกภายในอาเรย์ผ่านทาง index และด้วยคำสั่งวนซ้ำ หรือจะด้วยเมธอดของอาเรย์เอง อย่างไรก็ตาม ในภาษา Ruby นั้นยังมีเมธอดที่มีประโยชน์อีกเป็นจำนวนมากซึ่งคุณจะได้เรียนรู้ในบทต่อไป