检查Ruby中的数组以查看object.name是否存在

时间:2015-12-05 23:23:02

标签: ruby

我正在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

2 个答案:

答案 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中的实例变量@statusTasks
  • 用哈希值替换实例变量@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这样做的缺点是每个任务的名称都在两个地方(在列表哈希和相应的任务实例变量(哈希)中)。一般来说,这样的重复并不是一个好的编程实践。编码员可能会在这里提供建议。