• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

让Ruby的数组支持任意起始下标

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
我目前正在苦学《算法导论》。里面的堆排序算法是用数组表示一棵二叉树,就像这样
                       A[1]
                   /         \
            A[2]              A[3]
          /     \            /   \
     A[4]       A[5]    A[6]    A[7]
    /   \
A[8]   A[9]       


正如您所看到的,要求数组的起始下标为1才方便。可是Ruby的数组的起始下标是0。我们的想法是为Ruby的Array增加一个属性“base_index”属性,用它来获取或设置数组的起始下标。先看一下完成后的效果吧:
= ['a','b','c','d','e']
a.base_index  
#=> 0
a[0]  #=> 'a'
a[13]  #=> ['b','c','d']
a[1..4]  #=> ['b','c','d','e']
a[-1]  #=> 'e'

a.base_index 
= 1
a[
1]  #=> 'a'
a[13]  #=> ['a','b','c']
a[1..4]  #=> ['a','b','c','d']
a[0]  #=> 'e'

本来以为只要重新定义Array的[]和[]=操作符就行了,后来发现原来有n多函数需要重新定义呀!全部的实现代码如下(文件名:“dynimic_base_index.rb”)
  1# Enhances Array to support any base index.
  2# It provides a property "base_index", indicates the current base index of the array object.
  3# The value of "base_index" influnces [] operator
  4#    a = ['a','b','c','d','e']
  5#    a.base_index  #=> 0
  6#    a[0]  #=> 'a'
  7#    a[1, 3]  #=> ['b','c','d']
  8#    a[1..4]  #=> ['b','c','d','e']
  9#    a[-1]  #=> 'e'
 10#
 11#    a.base_index = 1
 12#    a[1]  #=> 'a'
 13#    a[1, 3]  #=> ['a','b','c']
 14#    a[1..4]  #=> ['a','b','c','d']
 15#    a[0]  #=> 'e'
 16#
 17# and []= operator
 18#    a = Array.new
 19#    a.base_index = 1
 20#    a[4] = "4";                 #=> [nil, nil, nil, nil, "4"]
 21#    a[1, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
 22#    a[2..3] = [ 1, 2 ]          #=> ["a", 1, 2, nil, "4"]
 23#    a[1, 2] = "?"               #=> ["?", 2, nil, "4"]
 24#    a[1..3] = "A"               #=> ["A", "4"]
 25#    a[0]   = "Z"               #=> ["A", "Z"]
 26#    a[2..0] = nil              #=> ["A"]
 27# 
 28# and these functions:
 29#    at()
 30#    delete_at()
 31#    each_index()
 32#    fetch()
 33#    fill()
 34#    index()
 35#    insert()
 36#    rindex()
 37#    slice()
 38#    slice!()
 39#    values_at()
 40#    indexes()
 41#    indices()
 42class Array
 43  alias original_index_reader []
 44  alias original_index_writer []=
 45  alias original_at at
 46  alias original_delete_at delete_at
 47  alias original_each_index each_index
 48  alias original_fetch fetch
 49  alias original_fill fill
 50  alias original_index index
 51  alias original_insert insert
 52  alias original_rindex rindex
 53  alias original_slice slice
 54  alias original_slice! slice!
 55  alias original_values_at values_at
 56  alias original_indexes indexes
 57  alias original_indices indices
 58  
 59  def base_index()
 60    return defined?(@base_index)? @base_index : 0
 61  end
 62  
 63  def base_index=(value)
 64    @base_index = value
 65  end
 66  
 67  def at(index)
 68    return original_at(index - base_index)
 69  end
 70  
 71  def [](*args)
 72    if args.length == 1 && args.original_at(0).is_a?(Fixnum) then  # e.g. a[1]
 73      return original_at(args.original_at(0)-base_index)
 74    elsif args.length == 1 && args.original_at(0).is_a?(Range) then  # e.g. a[1..3]
 75      range = Range.new(args.original_at(0).begin-base_index, 
 76                                 args.original_at(0).end-base_index, 
 77                                 args.original_at(0).exclude_end?)
 78      return original_index_reader(range)
 79    elsif args.length == 2  then  #e.g. a[1, 2]
 80      return original_index_reader(args.original_at(0)-base_index, 
 81                                             args.original_at(1))
 82    else
 83      return original_index_reader(*args)
 84    end
 85  end
 86  
 87  def []=(*args)
 88    if args.length >= 2 then 
 89      if args.original_at(0).is_a?(Fixnum) then  # e.g. a[1]='Y' or a[1,3] = 'Z' or a[1] = ['a','b'] or a[1..3] = ['a','b']
 90        return original_index_writer(args.original_at(0)-base_index, 
 91                                              *args.original_index_reader(1..args.length-1))
 92      elsif args.original_at(0).is_a?(Range) then # e.g. a[1..3] = 'Y' or a[1..3] = ['Y','Z']
 93        range = Range.new(args.original_at(0).begin-base_index, 
 94                                   args.original_at(0).end-base_index, 
 95                                   args.original_at(0).exclude_end?)
 96        return original_index_writer(range, 
 97                                              *args.original_index_reader(1..args.length-1))
 98      end
 99    end
100  end
101  
102  def delete_at(index)
103    return original_delete_at(index - base_index)
104  end
105  
106  def each_index
107    (0self.length).each do |i|
108      yield(i+base_index)
109    end
110    
111    return self
112  end
113  
114  def fetch(*args)
115    if args.length == 1  # e.g. a.fetch(1)  or  a.fetch(1) { |value| value**2 }
116      if block_given?
117        return yield(self.original_at(args.original_at(0) - base_index))
118      else
119        return self.original_at(args.original_at(0) - base_index)
120      end
121    else  # e.g. a.fetch(5, 'cat')
122      return original_fetch(args.original_at(0)-base_index, 
123                                   *args.original_index_reader(1..args.length-1))
124    end
125  end
126  
127  def fill(*args)
128    if block_given? then
129      if args.length == 0 then  # e.g. a.fill {|i| i*i }
130        start_index = base_index
131        end_index = base_index + self.length - 1
132      elsif args.length == 1 && args.original_at(0).is_a?(Range)==false then  #e.g. a.fill(2) {|i| i*i }
133        start_index = args.original_at(0)
134        end_index = base_index + self.length - 1
135      elsif args.length == 1 && args.original_at(0).is_a?(Range) then  # e.g. a.fill(2..5) {|i| i*i }
136        start_index = args.original_at(0).begin
137        end_index = args.original_at(0).exclude_end?? args.original_at(0).end-1 : args.original_at(0).end
138      elsif args.length == 2 then  # e.g. a.fill(2,2) {|i| i*i }
139        start_index = args.original_at(0)
140        end_index = start_index + args.original_at(1- 1
141      else
142        original_fill(*args)  # original_fill will raise exception :)
143      end
144      (start_index..end_index).each do |i|
145        self[i] = yield(i)
146      end
147    else 
148      if args.length == 1  # e.g. a.fill('x') 
149        obj = args.original_at(0)
150        start_index = base_index
151        end_index = base_index + self.length - 1
152      elsif args.length == 2 && args.original_at(1).is_a?(Range)==false  # e.g. a.fill('x', 2)
153        obj = args.original_at(0)
154        start_index = args.original_at(1)
155        end_index = base_index + self.length - 1
156      elsif args.length == 2 && args.original_at(1).is_a?(Range)  # e.g. a.fill('x', 2..5)
157        obj = args.original_at(0)
158        start_index = args.original_at(1).begin
159        end_index = args.original_at(1).exclude_end?? args.original_at(1).end-1 : args.original_at(1).end
160      elsif args.length == 3 # e.g. a.fill('x', 2, 2)
161        obj = args.original_at(0)
162        start_index = args.original_at(1)
163        end_index = start_index + args.original_at(2- 1
164      else
165        original_fill(*args)  # original_fill will raise exception :)
166      end
167      original_fill(obj, Range.new(start_index-base_index, end_index-base_index, false))
168    end
169      
170    return self
171  end
172  
173  def index(value)
174    result = original_index(value) 
175    return result && (result + base_index)
176  end
177  
178  def indexes(*args)
179    arguments = Array.new
180    
181    args.each do |arg|
182      if arg.is_a?(Range)
183        range = Range.new(arg.begin-base_index, 
184                                   arg.end-base_index, 
185                                   arg.exclude_end?)
186        arguments << range
187      else
188        arguments << arg-base_index
189      end
190    end
191    
192    return original_indexes(*arguments)
193  end
194  
195  def indices(*args)
196    arguments = Array.new
197    
198    args.each do |arg|
199      if arg.is_a?(Range)
200        range = Range.new(arg.begin-base_index, 
201                                   arg.end-base_index, 
202                                   arg.exclude_end?)
203        arguments << range
204      else
205        arguments << arg-base_index
206      end
207    end
208    
209    return original_indices(*arguments)
210  end
211  
212  def insert(*args)
213    if args.length >= 1 
214      original_insert(args.original_at(0)-base_index, 
215                         *args.original_index_reader(1..args.length-1))
216    else
217      original_insert(*args)  # original_insert will raise exception :)
218    end    
219  end
220  
221  def rindex(value)
222    result = original_rindex(value)
223    return result && (result + base_index)
224  end
225  
226  def slice(*args)
227    return self[

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Ruby 2.0.0 首个稳定版本(p0)发布发布时间:2022-07-14
下一篇:
Linux 安装ruby编译环境发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap