Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

وحدة 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)     # مرّر الـ block مباشرةً
  end
end

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

التحدي

سهل

أكمل الصنف Playlist. فهو يحتوي على كائنات Song (مع title وseconds) تتم إضافتها باستخدام add، ويتضمن Enumerable ويعرّف each، الذي يُنتج كل أغنية بالترتيب الذي أُضيفت به.

يضيف الكود المُ supplied أغنية واحدة لكل سطر إدخال (title,seconds)، ثم يستخدم فقط أساليب Enumerable على قائمة التشغيل: يطبع عدد الأغاني، والعناوين مفصولة بفواصل، والمدة الإجمالية بتنسيق m:ss، وعنوان أطول أغنية، وعناوين الأغاني التي تتجاوز 3 دقائق، مرتبة أبجديًا (أو none).

ضع الكود الخاص بك في song.rb وplaylist.rb. يحتوي main.rb على كود الإدخال/الإخراج المُ supplied ولا يمكن تعديله.

جرّب بنفسك

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 عبر الإنترنت