我正在Ruby中制作一个待办事项列表程序。我已经声明了两个类List和Task。使用空数组初始化List,而Task在创建新任务时具有名称和状态(状态初始化为“不完整”)。我想编辑createtask方法,以便我可以检查List的任务数组以查看任务是否已经存在以及是否存在我不想创建新任务。我该怎么做?
class Task
attr_accessor :name, :status
def initialize(name, status="incomplete")
@name = name
@status = status
end
def to_s
"#{name.capitalize}: #{status.capitalize}"
end
end
class List
attr_accessor :tasksarray
def initialize
@tasksarray = []
end
def create_task(name)
new_task = Task.new(name)
tasksarray.push(new_task)
puts "New task #{new_task.name} has been added with status #{new_task.status}"
end
答案 0 :(得分:0)
可以帮助您的方法是detect
(它在“可枚举”混音中也称为find
,方法相同,名称不同)。
使用它将列表中的每个元素传递给一个块,它将找到块返回true
的第一个元素。
如果未找到任何元素,则返回nil
。
在您的情况下,您想要检查一个元素是否与您给出的元素具有相同的名称:
existing_task = @tasksarray.detect { |task| task.name == name }
if existing_task
puts "Not adding new task, found existing task with status #{ existing_task.status }"
else
new_task = Task.new(name)
@tasksarray.push(new_task)
puts "New task #{new_task.name} has been added with status #{new_task.status}"
end
您可以使用Enumerable#any吗?
答案 1 :(得分:0)
您在问题中留下的评论表明您只需要一个任务列表。您可以通过创建类List
来实现,但您不会创建该类的实例。相反,类本身将在类实例变量中保存任务列表。请考虑以下事项。
<强>代码强>
class Task
attr_accessor :name, :status
def initialize(name, status)
@name = name
@status = status
end
end
class List
singleton_class.send(:attr_reader, :tasks)
@tasks = []
def self.create_task(name, status="incomplete")
return nil if tasks.any? { |task| task.name == name }
new_task = Task.new(name, status)
tasks << new_task
new_task
end
end
请注意,我已删除了puts
语句。这使得方法更加健壮。我们可以用另外的方法提供解释:
def explain(name, task)
if task
puts "New task '#{name}' with status '#{task.status}' has been added"
else
puts "'#{name}' is already in the list of tasks"
end
end
<强>实施例强>
name = "Take out the papers"
task = List.create_task(name, "will do soon")
#=> #<Task:0x007ffa2a161058 @name="Take out the papers", @status="will do soon">
explain(name, task)
# New task 'Take out the papers' with status 'will do soon' has been added
name = "and the trash"
task = List.create_task(name)
#=> #<Task:0x007ffa2a149f20 @name="and the trash", @status="incomplete">
explain(name, task)
# New task 'and the trash' with status 'incomplete' has been added
name = "Take out the papers"
task = List.create_task(name)
#=> nil
explain(name, task)
# 'Take out the papers' is already in the list of tasks
List.tasks
#=> [#<Task:0x007ffa2a161058 @name="Take out the papers", @status="will do soon">,
# #<Task:0x007ffa2a149f20 @name="and the trash", @status="incomplete">]
List.tasks[1].name
#=> "and the trash"
<强>讨论强>
请注意,由于我们不会创建List
的实例,因此该类没有initialize
方法。这一行:
singleton_class.send(:attr_reader, :tasks)
将带有参数:tasks
的方法Module#attr_reader发送到List
的单例类,从而为@tasks
创建一个getter。通常做的其他三种方式是:
singleton_class.class_eval{attr_reader :tasks}
和
class << self
attr_reader :tasks
end
和
module A
attr_reader :tasks
end
class Klass
extend A
end
改善我们拥有的东西
由于我们既没有创建List
的实例也没有为该类创建子类,我们可以将List
作为一个模块,这会引起人们注意我们没有使用区分a的属性的事实来自模块的课程。
不是拥有实例变量@name
和@status
,而是拥有一个哈希的实例变量,我们可能会调用@task
。除此之外,如果以后我们希望添加其他任务属性,那将更容易。
要确定某个任务是否在任务列表中,我们需要逐步执行一个数组。如果有很多任务,那将是相对低效的。我们可以通过使列表成为哈希来大大提高速度,哈希的键是任务的名称,其值是任务实例。这样,我们只需检查哈希是否有一个密钥name
,这非常快。 1 。
总而言之,让我们执行以下操作:
@name
中的实例变量@status
和Tasks
。@task
。List
成为一个模块,而不是一个类。修改代码
class Task
attr_accessor :task
def initialize(name, status)
@task = { name: name, status: status }
end
end
module List
singleton_class.send(:attr_reader, :tasks)
@tasks = {}
def self.create_task(name, status = 'incomplete')
return nil if tasks.key?(name)
task = Task.new(name, status)
@tasks[name] = task
task
end
end
def explain(name, task)
if task
puts "New task '#{name}' with status '#{task.task[:status]}' has been added"
else
puts "'#{name}' is already in the list of tasks"
end
end
实施例
name = "Take out the papers"
task = List.create_task(name, "real soon now")
#=> #<Task:0x007f802305cf30 @task={:name=>"Take out the papers",
# :status=>"real soon now"}>
explain(name, task)
# New task 'Take out the papers' with status 'real soon now' has been added
name = "and the trash"
task = List.create_task(name)
#=> #<Task:0x007f8023045088 @task={:name=>"and the trash",
# :status=>"incomplete"}>
explain(name, task)
# New task 'and the trash' with status 'incomplete' has been added
name = "Take out the papers"
task = List.create_task(name)
#=> nil
explain(name, task)
# 'Take out the papers' is already in the list of tasks
List.tasks
#=> {"Take out the papers"=>#<Task:0x007f802305cf30
# @task={:name=>"Take out the papers", :status=>"real soon now"}>,
# "and the trash"=>#<Task:0x007f8023045088
# @task={:name=>"and the trash", :status=>"incomplete"}>}
List.tasks["Take out the papers"].task[:status]
#=> "real soon now"
1这样做的缺点是每个任务的名称都在两个地方(在列表哈希和相应的任务实例变量(哈希)中)。一般来说,这样的重复并不是一个好的编程实践。编码员可能会在这里提供建议。