เมื่อคุณปฏิบัติต่อคอลเลกชันของคุณเป็นตัวแจงนับ คุณจะสามารถใช้ฟังก์ชันโปรดทั้งหมดของคุณ เช่น #map และ #reduce โดยไม่ต้องเขียนโค้ดเพิ่มเติมใดๆ มันสุดยอดมาก
ในสมัยก่อน การกำหนดตัวแจงนับค่อนข้างยุ่งยาก คุณต้องสร้างคลาสใหม่ รวมโมดูลที่นับได้ และกำหนดฟังก์ชัน #each
นับตั้งแต่ Ruby 1.9 เป็นต้นไป เรามีวิธีการระบุตัวแจงนับแบบง่ายๆ ที่เบากว่ามาก มาดูกันเลย
แนะนำคลาส Enumerator
คลาส Enumerator ให้คุณกำหนดตัวแจงนับแบบครั้งเดียว โดยใช้ไวยากรณ์บล็อก ในตัวอย่างด้านล่าง เราสร้างตัวแจงนับที่ส่งคืนชุดตัวเลขสุ่มแบบอนันต์
e = Enumerator.new do |y|
loop do
y << rand(10) # The << operator "yields" a value.
end
end
# Make the enumerator "yield" 10 values, then stop
puts e.first(10).inspect # => [6, 6, 7, 2, 2, 9, 6, 8, 2, 1]
คุณอาจสังเกตเห็นว่าเรากำลังใช้ตัวดำเนินการกะ <<
ในทางที่แปลก นี่คือทางลัดสำหรับ y.yield
กระบวนการ. คุณจะเรียกมันสำหรับแต่ละรายการในการแจงนับ หากทั้งหมดนี้ดูเป็นเรื่องมหัศจรรย์สำหรับคุณ ก็ไม่ต้องกังวล มันคือ.
ขนาดคอลเลกชัน
การหาขนาดของคอลเลกชันทำให้เกิดปัญหาสำหรับผู้แจงนับขี้เกียจของ Ruby ในการนับรายการในคอลเล็กชัน คุณต้องโหลดทั้งคอลเล็กชัน - ซึ่งขัดกับประเด็นทั้งหมดของการใช้ตัวแจงนับขี้เกียจ
มีวิธีแก้ปัญหาอยู่บ้าง หากคุณทราบขนาดของคอลเลกชันในขณะที่คุณสร้าง Enumerator คุณสามารถระบุได้
# You can pass the length as an argument to the constructor, if you have it
e = Enumerator.new(10) do |y|
10.times { y << rand }
end
ตัวอย่างในชีวิตจริงของฉัน
เมื่อวานฉันกำลังทำงานกับไซต์เอกสารใหม่ของฮันนี่แบดเจอร์ มันสร้างขึ้นโดยใช้ Jekyll และฉันกำลังเขียนปลั๊กอินเพื่อสร้างสารบัญตาม <h2>
และ <h3>
ในเอกสารประกอบ
มันค่อนข้างอึดอัดที่จะรู้ว่า <h3>
. ตัวไหน แท็กอยู่ในส่วนที่กำหนดโดย <h2>
แท็ก คุณต้องแยกวิเคราะห์ HTML โดยใช้ nokogiri แล้วสแกนเอกสารผลลัพธ์ ดังนั้นฉันจึงแยกโค้ดนั้นออกและทำให้เป็นตัวแจงนับ นี่คือลักษณะที่ปรากฏ
def subheadings(el)
Enumerator.new do |y|
next_el = el.next_sibling
while next_el && next_el.name != "h2"
if next_el.name == "h3"
y << next_el
end
next_el = next_el.next_sibling
end
end
end