Menu
Coddy logo textTech

המודול Enumerable

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 30 מתוך 57.

Enumerable הוא המודול שמאחורי מתודות האוספים של מערכים וגיבובים. מחלקה שמגדירה את each, ומניבה את האיברים שלה בזה אחר זה, וכוללת את Enumerable, מקבלת את map, select, count, sort_by, min_by, sum, include? ועוד עשרות מתודות:

class Playlist
  include Enumerable

  def initialize(*songs)
    @songs = songs
  end

  def each
    @songs.each { |song| yield song }
  end
end

list = Playlist.new("Intro", "Dune", "Outro")
puts list.map(&:upcase).join(", ")
puts list.select { |s| s.size > 4 }.inspect
puts list.count
puts list.include?("Dune")

פלט:

INTRO, DUNE, OUTRO
["Intro", "Outro"]
3
true

yield מעביר ערך לבלוק שהקורא העביר ל-each. המחלקה קובעת מהו אלמנט אחד, למשל שורת טקסט, זוג ערכים או אחד מהאובייקטים שלה:

class Inventory
  include Enumerable

  def initialize
    @stock = { "apple" => 3, "pear" => 0, "plum" => 7 }
  end

  def each
    @stock.each { |name, qty| yield name, qty }
  end
end

inv = Inventory.new
p inv.select { |_, qty| qty.positive? }.map(&:first)
p inv.max_by { |_, qty| qty }

פלט:

["apple", "plum"]
["plum", 7]

אין צורך לאחסן את האיברים. each יכול לחשב אותם תוך כדי התקדמות, ומתודות כמו first עוצרות את הלולאה מוקדם:

class Squares
  include Enumerable

  def initialize(limit)
    @limit = limit
  end

  def each
    n = 1
    while n * n <= @limit
      yield n * n
      n += 1
    end
  end
end

p Squares.new(50).to_a
p Squares.new(1000).first(3)
puts Squares.new(100).sum

פלט:

[1, 4, 9, 16, 25, 36, 49]
[1, 4, 9]
385

כאשר האיברים מגדירים את <=>, שיטות המיון של Enumerable, כגון sort, min ו-max, פועלות ללא בלוק. אחרת הן מקבלות בלוק, כמו sort_by ו-min_by:

class Team
  include Enumerable

  def each(&block)
    @players.each(&block)     # העבר את הבלוק הלאה ישירות
  end
end

team.sort_by(&:age)
team.min_by(&:score)
challenge icon

אתגר

קל

השלימו את המחלקה Playlist. היא מכילה אובייקטים מסוג Song (עם title ו-seconds) שמוסיפים באמצעות add, כוללת את Enumerable ומגדירה את each, שמניבה כל שיר לפי סדר הוספתו.

הקוד שסופק מוסיף שיר אחד לכל שורת קלט (title,seconds), ואז משתמש רק במתודות של Enumerable על רשימת ההשמעה: הוא מדפיס את מספר השירים, את הכותרות כשהן מופרדות בפסיקים, את משך הזמן הכולל בפורמט m:ss, את הכותרת הארוכה ביותר ואת הכותרות של שירים שאורכם עולה על 3 דקות, ממוינות בסדר אלפביתי (או none).

הקוד שלכם ייכתב בקבצים song.rb ו-playlist.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.

נסו בעצמכם

require_relative 'song'
require_relative 'playlist'

# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input = []
while (line = gets)
  input << line.chomp
end
list = Playlist.new
input.each do |line|
  title, seconds = line.split(",")
  list.add(Song.new(title, seconds.to_i))
end
total = list.sum(&:seconds)
long = list.select { |s| s.seconds > 180 }.map(&:title).sort
puts "songs: #{list.count}"
puts "titles: #{list.map(&:title).join(", ")}"
puts format("total: %d:%02d", total / 60, total % 60)
puts "longest: #{list.max_by(&:seconds).title}"
puts "over 3 min: #{long.empty? ? "none" : long.join(", ")}"
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Ruby אונליין