Есть ли умный способ проверить, находится ли пользовательский объект в массиве? - PullRequest
1 голос
/ 20 января 2012

Учитывая, что у меня есть массив arr экземпляров пользовательского класса My_class. Этот класс имеет несколько различных переменных экземпляра. Давайте назовем их :name (строка), :is_processed (логическое значение) и :date ( DateTime ). Все они читабельны.

Как лучше всего проверить, находится ли другой заданный экземпляр My_class (назовите его newbe) в массиве на основе содержимого вышеупомянутых переменных экземпляра?

Использование arr.include?(newbe) не сработает, поскольку при этом сравниваются идентификаторы объектов, не так ли?
Могу ли я переопределить способ Array#include? сравнения двух объектов?


Говоря в коде

class My_class
  attr_reader :name, :is_processed, :date

  def initialize(_name, _proc, _d)
    @name = _name
    @is_processed = _proc
    @date = _d
  end
end

где-то еще

first = My_class.new("First", false, DateTime.new(2001,2,3,4,5,6))
second = My_class.new("Second", true, DateTime.new(2001,2,3,4,5,6))
third = My_class.new("Third", false, DateTime.new(2001,2,3,3,2,1))
newbe = My_class.new("Second", true, DateTime.new(2001,2,3,4,5,6))

arr = [first, second, third]
arr.include?(newbe)  # => false but should be true

Ответы [ 3 ]

3 голосов
/ 20 января 2012

Вы хотите сравнить экземпляры своего класса, поэтому включите comparable, определите метод <=>, и вы добавили эти методы к своим экземплярам класса:

<, <=, ==,>,> =, между? (#include? использует # ==).

require 'date'
class My_class
  include Comparable
  attr_reader :name, :is_processed, :date

  def initialize(_name, _proc, _d)
    @name = _name
    @is_processed = _proc
    @date = _d
  end

  def <=>(other)
    [self.name, self.is_processed, self.date]<=>[other.name, other.is_processed, other.date]
  end
end
first = My_class.new("First", false, DateTime.new(2001,2,3,4,5,6))
second = My_class.new("Second", true, DateTime.new(2001,2,3,4,5,6))
third = My_class.new("Third", false, DateTime.new(2001,2,3,3,2,1))
newbe = My_class.new("Second", true, DateTime.new(2001,2,3,4,5,6))

arr = [first, second, third]
p arr.include?(newbe)  # => true
#you could do arr.sort, but they are sorted allready by accident...
2 голосов
/ 20 января 2012

Вам следует подумать, имеет ли смысл переопределить == для вашего пользовательского класса, например:

class My_class
  def ==(other)
    (other.is_a? My_class) && 
    (other.name == @name)  &&
    (other.is_processed == @is_processed) &&
    (other.date == @date)
  end
end

Если вы сделаете это, Array # include? будет работать так, как вы хотите.

2 голосов
/ 20 января 2012

Используйте any? с блоком.

my_arr.any? { |o| o.kind_of?(MyClass) }

Вы также можете использовать detect или find, если хотите вернуть сопоставленный объект. Это все стандартные методы в Enumerable, в которые смешивается большинство классов коллекции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...