replacing 'eval' with a better solution
This method works, but it works very slowly. I think one of the problems might be the 'eval' statements in the add_by
method.
Some explanation: every Node object has three relevant attributes, :x
, :y
and :neighbors
. :x
and :y
are integers representing planar coordinates, :neighbors
is an array, and nodes are stored in the @nodes
array. The goal is to find, for each node k
in @nodes
, the nodes that are within some distance d
of k
and add them to the @neighbors
array of k
.
def set_neighbors d
def add_by dim, d
dict = {}
@nodes.each{|k| dict[k] = []}
@nodes.each_index do |k|
up = k+1
down = k-1
while up < @nodes.length and ((eval '@nodes[k].'+ dim) - (eval '@nodes[up].'+dim)).abs <= d
dict[@nodes[k]].push(@nodes[up])
up += 1
end
while down >= 0 and ((eval '@nodes[k].'+ dim) - (eval '@nodes[down].'+dim)).abs <= d
dict[@nodes[k]].push(@nodes[down])
down -= 1
开发者_如何学编程 end
end
return dict
end
@nodes.sort_by{|k| k.x}
exis = add_by('x', d)
whys = add_by('y', d)
@nodes.each do |k|
neighbors = exis[k]&whys[k]
k.neighbors = neighbors.select{|j| planar_distance(j,k) <= d}
end
end
My question is, how would you do this without either repeating the add_by
routine for x
and y
or using eval?
You can avoid eval by using @nodes[k].send dim.to_sym
.
I'm not sure what your code is doing exactly, but maybe a few pointers:
def set_neighbors d
@nodes.each do |node|
node.neighbors = @nodes.select do |n|
(node.x - n.x).abs <= d &&
(node.x - n.x).abs <= d &&
planar_distance(n,node) <= d
end - node
end
end
How would I do it? I'd use the Neo4J graph database via the neo4j gem (source). If you're concerned about performance, this is optimized for graph distance calculations. Also the API is very nice.
That being said, you really don't need eval at all. You can call a calculated method name on an object by using send
. So you can replace the above with @nodes[k].send(dim)
, @nodes[up].send(dim)
, etc.
精彩评论