欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在 Ruby 中对树状结构(tree)进行 map 操作 博客分类: Ruby rubytreemap 

程序员文章站 2024-02-12 14:22:40
...
class BookChapter < ActiveRecord::Base
  belongs_to :parent, :class_name => 'BookChapter', :foreign_key => 'parent_id'

  has_many :children, 
    :class_name => 'BookChapter', 
    :foreign_key => 'parent_id',
    :order => 'play_order'

  def map(parent_mapping=nil, &block)
    result = block.call self, parent_mapping
    children.each do |chapter|
      chapter.map result, &block
    end
    result
  end

end


usage:

class EpubChapter
  attr_accessor :title
  def initialize
    @children = []
  end

  def add_child(child)
    @children << child
  end
end

book_chapter = BookChapter.first
book_chapter.map do |chapter, parent|
  # 这里处理父子关系,例如:
  child = EpubChapter.new
  child.title = chapter.title
  parent.add_child child if parent
  child
end


这是改进过之后的版本了,之前一个版本使用简单些,但是有接口上的双向依赖,就不贴出来了。

然后呢,还可以把这个方法抽出来,放到 module 中,这样就可以到处使用了:
module MappableTree
  def map(parent_mapping=nil, &block)
    result = block.call self, parent_mapping
    children.each do |child|
      child.map result, &block
    end
    result
  end
end

class Nokogiri::XML::Node
  include MappableTree
end


还有点味道,这个 map 方法要求实现类必须有一个 children 方法,而且这个 children 方法的返回值还必须有一个 each 方法,稍微封装一下,变成:
module MappableTree
  def map(parent_mapping=nil, &block)
    result = block.call self, parent_mapping
    each_child do |child|
      child.map result, &block
    end
    result
  end
end

class Nokogiri::XML::Node
  include MappableTree
  def each_child &block
    children.each &block
  end
end

这样耦合就不那么紧了。
相关标签: ruby tree map