在新结构中快速创建结构列表

时间:2013-12-13 22:52:11

标签: ruby struct graph-algorithm

我正在尝试构建一些原始对象来存储图形:

Vertex = Struct.new(:parent, :rank)
Graph = Struct.new(:vertexes, :edges)
Edge = Struct.new(:weight, :endpoints)

这里的想法是:endpoints(和:parent)是顶点,当然,Graph存储顶点和边的列表。我试图设置它,我遇到了麻烦:

[47] pry(main)> t_graph = Graph.new()
=> #<struct Graph vertexes=nil, edges=nil>
[48] pry(main)> t_graph[:vertexes] = Array.new(Vertex.new())
TypeError: can't convert Vertex into Integer
from (pry):48:in `initialize'

另一方面,这有效:

[49] pry(main)> t_graph[:vertexes] = [Vertex.new(), Vertex.new()]
=> [#<struct Vertex parent=nil, rank=nil>,
 #<struct Vertex parent=nil, rank=nil>]

在图表(或任何此类关系)中生成大量空顶点以进行测试的有效方法是什么?

3 个答案:

答案 0 :(得分:2)

Array.new不是使用值初始化数组的标准方法。如果要使用Vertex实例创建数组,请使用

t_graph[:vertexes] = [Vertex.new]

如文档中所述,Array.new采用阵列的数组或Fixnum大小。

new(size=0, obj=nil)
new(array)
new(size) {|index| block }
     

返回一个新数组。

     

在第一种形式中,如果没有发送参数,则新数组将是   空。发送大小和可选obj时,会创建一个数组   与obj的大小副本。请注意所有元素都会引用   同一个对象obj。

     

第二种形式创建作为参数传递的数组的副本(   通过在参数上调用#to_ary来生成数组。

还有一件事:当没有args时你可以省略括号。

t_graph[:vertexes] = [Edge.new, Edge.new]

而不是

t_graph[:vertexes] = [Edge.new(), Edge.new()]

请记住,您可以向Structs添加方法。

Graph = Struct.new(:vertexes, :edges) do
  def add_vertex(vertex)
    self.vertexes ||= []
    self.vertexes <<  vertex
  end
end

g = Graph.new
g.add_vertex(Vertex.new)

答案 1 :(得分:1)

我不同意Array.new在这里没用。在下面找到解决海报问题的用例,即使已经显示但上面没有很好地解释:

  [31] pry(main)> Vertex = Struct.new(:parent, :rank)
  => Vertex
  [32] pry(main)> Graph = Struct.new(:vertexes, :edges)
  => Graph
  [33] pry(main)> Edge = Struct.new(:weight, :endpoints)
  => Edge
  [34] pry(main)> t_graph = Graph.new()
  => #<struct Graph vertexes=nil, edges=nil>
  [35] pry(main)> t_graph[:vertexes] = Array.new(2) { Vertex.new }
  => [#<struct Vertex parent=nil, rank=nil>, #<struct Vertex parent=nil, rank=nil>]
  [36] pry(main)> t_graph[:vertexes] = Array.new(2, Vertex.new )
  => [#<struct Vertex parent=nil, rank=nil>, #<struct Vertex parent=nil, rank=nil>]

如第[35]行所示,您可以调用Array.new,在这种情况下提供数组中所需的元素数量2以及在这种情况下元素应该是Vertex.new

詹姆斯·爱德华·格雷二世(James Edward Gray)就Avdi Grimm的播客(此处没有广告意图)进行了一次演讲,清楚地解释了一个非常相似的例子

答案 2 :(得分:0)

简单填充Vertexes列表的一种方法是使用.times,这看起来有点笨拙,但会创建一个列表(我添加了:id值):

t_verts = []
9.times do t_verts << Vertex.new end
[10] pry(main)> t_verts
=> [#<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>,
 #<struct Vertex parent=nil, rank=nil, id=nil>]

这会创建不同的对象。

[11] pry(main)> t_verts.each do |vert|
[11] pry(main)*   vert.id = rand  
[11] pry(main)* end  
=> [#<struct Vertex parent=nil, rank=nil, id=0.755245226082449>,
 #<struct Vertex parent=nil, rank=nil, id=0.0167377598961559>,
 #<struct Vertex parent=nil, rank=nil, id=0.759799975185007>,
 #<struct Vertex parent=nil, rank=nil, id=0.613897002692335>,
 #<struct Vertex parent=nil, rank=nil, id=0.0407847317079812>,
 #<struct Vertex parent=nil, rank=nil, id=0.549475744759297>,
 #<struct Vertex parent=nil, rank=nil, id=0.571876769381891>,
 #<struct Vertex parent=nil, rank=nil, id=0.270800829904956>,
 #<struct Vertex parent=nil, rank=nil, id=0.814754555208641>]

要将这些集体添加到图表中,可以使用Simone的方法将Vertexes列表添加到图表中:

def add_vertex(new_verts) # Adds or updates vertexes non-destructively
    new_verts.each do |new_vert|
      # first case, redundant insert
      if self.vertexes.include?(new_vert)
        warn "Vertex already exists in graph, no replacement done"
        # second case, update
      elsif not (update_vert = self.vertexes.select { |vert| vert.id == new_vert.id }).empty?
        self.vertexes[self.vertexes.index(update_vert)] = new_vert
        # third case, append new
      else
        self.vertexes ||= []
        self.vertexes << vertex
      end
    end
  end

看起来我需要构建一个构造函数方法,从邻接列表和权重列表构建Graph;我没有看到一个简单的方法,一步到位。