1

Is there a fast and clean way of returning a JSON hash back from any node in a Ruby on Rails' acts_as_nested_set without using recursion?

Here's the recursive solution for reference:

class Node < ActiveRecord::Base
  has_many :products
  def json_hash
    if children.size > 0
      children.collect { |node| { node.name => node.json_hash }.to_json
    else
      { node.name => node.products.find(:all).collect(&:name) }.to_json
    end
  end
end
4

2 回答 2

2

有一篇关于树遍历的维基百科文章显示了您正在使用的递归解决方案的不同替代方案。在您的特定情况下使用它们可能会很棘手,但应该是可能的。

但是,我对您的问题是,您是否有特定的原因要使用迭代而不是递归?我认为任何迭代解决方案都不会那么干净。您的树是否太大以至于您的堆栈空间不足(它们必须非常大)?否则,我不太确定迭代解决方案是否真的会更快。

不过,如果您看到性能问题,我看到了一种改进的潜力......但我不知道 rails,所以我不确定它是否准确:

find 方法是否返回一个新数组?如果是这样,您可能想要调用 .collect!而不是 .collect,因为如果 find 创建了一个数组,那么您只是在创建一个数组,然后将其丢给 collect 的调用(这也会创建一个数组),这肯定不会非常有效并且可能会减慢您的速度如果你在那里有一棵大树,很多。

所以

{ node.name => node.products.find(:all).collect(&:name) }.to_json

可能变成

{ node.name => node.products.find(:all).collect!(&:name) }.to_json

编辑:此外,创建散列散列可能更有效,然后一举将整个事物转换为 json,而不是像您正在做的那样将其转换为碎片邮件。

所以

class Node < ActiveRecord::Base
  has_many :products
  def json_hash
    if children.size > 0
      children.collect { |node| { node.name => node.json_hash }.to_json
    else
      { node.name => node.products.find(:all).collect!(&:name) }.to_json
    end
  end
end

可能变成

class Node < ActiveRecord::Base
  has_many :products
  def json_hash
    to_hash.to_json
  end

  def to_hash
    if children.size > 0
      children.collect { |node| { node.name => node.to_hash }
    else
      { node.name => node.products.find(:all).collect!(&:name) }
    end
  end
end

这是否有效并且更有效,我留给你作为练习;-)

于 2008-09-03T07:24:35.383 回答
1

JSON 化!

node.to_json(:include=>{:products=>{:include=>:product_parts}})
于 2010-08-27T20:26:13.187 回答