【问题标题】:ruby objects that know of their collection/array知道其集合/数组的红宝石对象
【发布时间】:2012-12-06 03:07:49
【问题描述】:

我有一组对象,比如“人”,它们彼此之间存在关系。我希望能够从一个人到另一个人,这将是数组中的另一个对象。

所以我想出了这个:

class Person
  attr_accessor :name, :parent, :collection
  def parents
    rtn = []
    pid = @parent
    while pid
      p = collection.select{|i|i.name == pid}.first
      if p 
        rtn << p
        pid = p.parent
      else
        pid = nil
      end
    end
    rtn
  end
  def to_s;@name;end
end
class PersonCollection < Array
  def <<(obj)
    obj.collection = self
    super
  end
end

...这让我可以这样做:

p1 = Person.new
p1.name = 'Anna'
p2 = Person.new
p2.name = 'Bob'
p2.parent = 'Anna'
pc = PersonCollection.new
pc << p1
pc << p2
pp p2.parents   

请原谅我相当笨拙的例子。关键目标是让集合的成员能够访问同一集合的其他成员。有没有更好的办法?

【问题讨论】:

  • 对我来说听起来像是一个链表,所以您需要放弃该数组,或者根据您的需要创建一个链表数组。

标签: ruby algorithm oop design-patterns


【解决方案1】:

有没有更好的办法?

是的。使对象持有对其相关对象的引用:

class Person
  attr_accessor :name, :parent, :collection

  def parents
    if parent
      [parent].concat(parent.parents)
    else
      []
    end
  end

  def to_s
    name
  end
end

p1 = Person.new
p1.name = 'Anna'

p2 = Person.new
p2.name = 'Bob'
p2.parent = p1

p2.parents 现在返回[p1],没有数组遍历、字符串比较或PersonCollection

【讨论】:

  • 在我的现实世界问题中,父对象在创建子对象时可能不存在。不过我也许可以解决这个问题....
  • @Rob 所以?在答案中的示例用法中,直到创建对象后才分配父级。
  • 点是在创建和填充 p2 时 p1 存在。我没有那个。
  • @Rob 不,你错过了一点,它真的不需要:p2 = Person.new; p2.name = 'Bob'; p1 = Person.new; p1.name = 'Anna'; ... ; p2.parent = p1;
  • 当然可以。我的意思是,如果您在循环中,从文件中读取和创建 Person 对象,然后将它们放入数组中。您可以在最后扫描数组并找到父母并更新孩子等等。或者将查找构建到集合中(就像我的解决方案所做的那样)。是的,有利也有弊。你的回答很好,非常感谢。只是坚持一些更适用于我的案例的惊人的东西(我可能会失望)。
【解决方案2】:

使用 Hash 将是一种更好的方法,可以防止所有这些数组遍历。这是我使用第二个哈希记录和查找您的孤儿的解决方案:

class Person
  attr_accessor :name, :parent, :parent_key, :collection

  def parents
    if parent
      [parent].concat(parent.parents)
    else
      []
    end
  end

  def children
    self.collection.values.select{ |person| person.parent === self }
  end

  def descendants
    self.collection.values.select{ |person| person.parents.include? self }
  end

  def to_s
    self.name
  end
end

class PersonCollection < Hash
  attr_accessor :orphans

  def initialize
    self.orphans = Hash.new
    super
  end

  def store (key,obj)
    obj.collection = self
    if !obj.parent_key.nil?
        if self[obj.parent_key] 
            #this person's parent is already in the Hash
            obj.parent = self[obj.parent_key]
        else 
            #this person's parent is missing, so add this person to the orphans hash
            self.orphans[obj.parent_key] ||= []
            self.orphans[obj.parent_key] << obj
        end
    end
    if orphans[obj.name] 
        # this person has an array of orphans, so lets finally set their parents 
        self.orphans[obj.name].each do |orphan|
            orphan.parent = obj
        end

        # finally, clean up the hash after taking care of theses orphans
        self.orphans.delete(obj.name)
    end

    super
  end

end

总结一下我的方法:

  1. 如果一个人在被添加到集合时可以找到他/她的父母...宾果游戏。
  2. 如果一个人在添加到集合时找不到他/她的父母,他/她的对象将记录/存储在他/她父母姓名下的哈希self.orphans中。
  3. 如果一个人在他/她的名字下有孤儿在被添加到集合时,这些孤儿会更新,以便他们最终知道他们的父母。

【讨论】:

    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2019-04-03
    • 2012-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多