Menu
Coddy logo textTech

Benutzerdefinierte Collections

Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 40 von 57.

Eine Sammlungsklasse kombiniert mehrere spezielle Methoden: each mit Enumerable, << zum Hinzufügen, size sowie to_s und inspect zur Ausgabe. each sollte auch ohne Block funktionieren und mit to_enum einen Enumerator zurückgeben, wie es bei Arrays der Fall ist:

class TodoList
  include Enumerable

  def initialize
    @items = []
  end

  def <<(item)
    @items << item
    self
  end

  def each
    return to_enum(:each) unless block_given?

    @items.each { |item| yield item }
    self
  end
end

list = TodoList.new << "wash" << "shop" << "cook"
list.each.with_index(1) { |item, n| puts "#{n}. #{item}" }
p list.select { |i| i.include?("o") }

Ausgabe:

1. wash
2. shop
3. cook
["shop", "cook"]

block_given? gibt an, ob der Aufrufer einen Block übergeben hat. Der ohne Block zurückgegebene Enumerator unterstützt Verkettungen wie each.with_index, each_slice oder next:

class Countdown
  include Enumerable

  def initialize(from)
    @from = from
  end

  def each
    return to_enum(:each) unless block_given?

    @from.downto(1) { |n| yield n }
  end
end

e = Countdown.new(3).each
puts e.next
puts e.next
p Countdown.new(5).each_slice(2).to_a

Ausgabe:

3
2
[[5, 4], [3, 2], [1]]

to_s ist der benutzerfreundliche Text und inspect eine kurze Zusammenfassung für Programmierer. Bei einer Sammlung zeigt inspect normalerweise die Klasse und die Größe statt jedes einzelnen Elements:

class TodoList
  include Enumerable

  def initialize(*items)
    @items = items
  end

  def each(&block)
    @items.each(&block)
  end

  def size
    @items.size
  end

  def to_s
    map.with_index(1) { |item, n| "#{n}. #{item}" }.join("\n")
  end

  def inspect
    "#<TodoList #{size} items>"
  end
end

list = TodoList.new("wash", "shop")
puts list
p list

Ausgabe:

1. wash
2. shop
#<TodoList 2 Einträge>

Enumerable stellt count bereit, aber nicht size, empty?, << oder []: Diese gehören zur Klasse, da nur sie weiß, wie die Elemente gespeichert werden. Wenn du sie definierst, wirkt die Sammlung für ihre Aufrufer wie ein Array:

def size
  @items.size
end

def empty?
  @items.empty?
end

def [](index)
  @items[index]
end
challenge icon

Aufgabe

Einfach

Vervollständige die Klasse TodoList. << fügt einen Aufgabentext hinzu und gibt die Liste zurück. each liefert die Aufgaben und gibt ohne Block to_enum(:each) zurück. Binde Enumerable ein. size gibt die Anzahl der Aufgaben zurück. to_s gibt die Aufgaben als nummerierte Zeilen wie 1. wash oder nothing to do zurück, und inspect gibt #<TodoList 3 items> zurück.

Der bereitgestellte Code fügt jede Eingabezeile durch Verkettung von << hinzu und gibt anschließend die Liste, p der Liste, die mit ! nummerierten Aufgaben über each.with_index(1) wie 1! wash, die Anzahl der Aufgaben, die o enthalten, sowie die alphabetisch erste Aufgabe aus.

Dein Code gehört in todo_list.rb. main.rb enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

require_relative 'todo_list'

# Gelieferter Ein-/Ausgabe-Code: belasse ihn wie er ist
input = []
while (line = gets)
  input << line.chomp
end
list = input.reduce(TodoList.new) { |l, task| l << task }
puts list
p list
list.each.with_index(1) { |task, n| puts "#{n}! #{task}" }
puts "with o: #{list.count { |t| t.include?("o") }}"
puts "first: #{list.min}"
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Ruby-Compiler