Menu
CoddyTech

Module Enumerable

Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 30 trên 57.

Enumerable là module đứng sau các phương thức xử lý tập hợp của mảng và hash. Một lớp định nghĩa each, lần lượt trả về từng phần tử và bao gồm Enumerable sẽ có các phương thức map, select, count, sort_by, min_by, sum, include? và hàng chục phương thức khác:

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")

Đầu ra:

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

yield truyền một giá trị cho khối lệnh mà bên gọi đã đưa vào each. Lớp quyết định một phần tử là gì, chẳng hạn như một dòng văn bản, một cặp giá trị hoặc một trong những đối tượng của chính nó:

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 }

Đầu ra:

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

Các phần tử không cần phải được lưu trữ. each có thể tính chúng trong lúc duyệt, còn các phương thức như first sẽ dừng vòng lặp sớm:

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

Đầu ra:

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

Khi các phần tử định nghĩa <=>, các phương thức sắp xếp của Enumerable, như sort, min và max, hoạt động mà không cần khối lệnh. Nếu không, chúng cần một khối lệnh, như trong sort_by và min_by:

class Team
  include Enumerable

  def each(&block)
    @players.each(&block)     # chuyển thẳng khối lệnh (block) sang
  end
end

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

Thử thách

Dễ

Hoàn thiện lớp Playlist. Lớp này chứa các đối tượng Song (có title và seconds) được thêm bằng add, bao gồm Enumerable và định nghĩa each, phương thức này lần lượt trả về từng bài hát theo thứ tự được thêm vào.

Code được cung cấp thêm một bài hát cho mỗi dòng đầu vào (title,seconds), sau đó chỉ dùng các phương thức của Enumerable trên danh sách phát: in ra số bài hát, các tiêu đề được nối bằng dấu phẩy, tổng thời lượng theo định dạng m:ss, tiêu đề bài hát dài nhất và tiêu đề của những bài hát dài hơn 3 phút, được sắp xếp theo thứ tự bảng chữ cái (hoặc none).

Code của bạn nằm trong song.rb và playlist.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.

Tự làm thử

require_relative 'song'
require_relative 'playlist'

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Ruby online