我目前正在苦学《算法导论》。里面的堆排序算法是用数组表示一棵二叉树,就像这样
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 = ['a','b','c','d','e']
a.base_index #=> 0
a[0] #=> 'a'
a[1, 3] #=> ['b','c','d']
a[1..4] #=> ['b','c','d','e']
a[-1] #=> 'e'
a.base_index = 1
a[1] #=> 'a'
a[1, 3] #=> ['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()
42
class 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
(0
self.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[*args]
228
end
229
230
def slice!(*args)
231
result = self[*args]
232
delete_at(*args)
233
return result
234
end
235
236
def values_at(*args)
237
arguments = Array.new
238
239
args.each do |arg|
240
if arg.is_a?(Range)
241
range = Range.new(arg.begin-base_index,
242
arg.end-base_index,
243
arg.exclude_end?)
244
arguments << range
245
else
246
arguments << arg-base_index
247
end
248
end
249
250
return original_values_at(*arguments)
251
end
252
end
单元测试代码(文件名“TestDynimicBaseIndex.rb”)
1
require 'dynimic_base_index'
2
require 'test/unit'
3
4
class TestDynimicBaseIndex < Test::Unit::TestCase
5
def test_base_index
6
a = ['a','b','c','d','e']
7
assert_equal(0, a.base_index)
8
a.base_index = 1
9
assert_equal(1, a.base_index)
10
end
11
12
def test_index_reader_operator()
13
a = ['a','b','c','d','e']
14
15
assert_equal(0, a.base_index)
16
assert_equal('a', a[0])
17
assert_equal(['b','c','d'], a[1,3])
18
assert_equal(['b','c','d','e'], a[1..4])
19
assert_equal('e', a[-1])
20
21
a.base_index = 1
22
assert_equal(1, a.base_index)
23
assert_equal('a', a[1])
24
assert_equal(['a','b','c'], a[1,3])
25
assert_equal(['a','b','c','d'], a[1..4])
26
assert_equal('e', a[0])
27
assert_equal(nil, a[6])
28
assert_equal([], a[6,1])
29
assert_equal([], a[6..10])
30
assert_equal(nil, a[7,1])
31
end
32
33
def test_index_writer_operator()
34
a = ['a','b','c','d','e']
35
a.base_index = 1
36
a[1] = 'Y'
37
assert_equal(['Y','b','c','d','e'], a)
38
39
b = ['a','b','c','d','e']
40
b.base_index = 1
41
b[1,3] = ['Y','Z']
42
assert_equal(['Y','Z','d','e'], b)
43
44
c = ['a','b','c','d','e']
45
c.base_index = 1
46
c[1,3] = 'Y'
47
assert_equal(['Y','d','e'], c)
48
49
d = ['a','b','c','d','e']
50
d.base_index = 1
51
d[1..3] = 'Y'
52
assert_equal(['Y','d','e'], d)
53
54
e = ['a','b','c','d','e']
55
e.base_index = 1
56
e[1..3] = ['Y', 'Z']
57
assert_equal(['Y','Z','d','e'], e)
58
end
59
60
def test_at()
61
a = ['a','b','c','d','e']
62
assert_equal('a', a.at(0))
63
a.base_index = 1
64
assert_equal('a', a.at(1))
65
end
66
67
def test_delete_at()
68
a = ['a','b','c','d','e']
69
a.base_index = 1
70
assert_equal('a', a.delete_at(1))
71
assert_equal(['b','c','d','e'], a)
72
end
73
74
def test_each_index()
75
a = ['a','b','c','d','e']
76
expected_indexes = [1,2,3,4,5]
77
actual_indexes = Array.new
78
79
a.base_index = 1
80
81
a.each_index do |i|
82
actual_indexes << i
83
end
84
85
assert_equal(expected_indexes, actual_indexes)
86
end
87
88
def test_fetch()
89
a = [ 11, 22, 33, 44 ]
90
a.base_index = 1
91
92
assert_equal(11, a.fetch(1))
93
assert_equal(44, a.fetch(0))
94
assert_equal(121, a.fetch(1) { |value| value**2 } )
95
96
assert_equal('cat', a.fetch(5, 'cat'))
97
end
98
99
def test_fill()
100
a = [ "a", "b", "c", "d" ]
101
a.base_index = 1
102
103
assert_equal(["x","x","x","x"], a.fill("x"))
104
assert_equal(["x","y","y","y"], a.fill("y", 2))
105
assert_equal(["x","z","z","y"], a.fill("z", 2, 2))
106
assert_equal(["x","a","a","a"], a.fill("a", 2..4))
107
108
a = [ "a", "b", "c", "d" ]
109
a.base_index = 1
110
assert_equal([1,4,9,16], a.fill { |i| i*i })
111
assert_equal([1,8,18,32], a.fill(2) { |i| a[i]*2 })
112
assert_equal([1,4,9,32], a.fill(2,2) { |i| a[i]/2 })
113
assert_equal([1,4,6,8], a.fill(2..4) { |i| i*2 })
114
end
115
116
def test_index()
117
a = [ "a", "b", "c", "d" ]
118
a.base_index = 1
119
assert_equal(2, a.index('b'))
120
assert_equal(nil, a.index('x'))
121
end
122
123
def test_insert()
124
a = [11,22,33]
125
a.base_index = 1
126
assert_equal([11,22,33], a.insert(2))
127
assert_equal([11,'a',22,33], a.insert(2, 'a'))
128
assert_equal([11,['!','@'],'a',22,33], a.insert(2, ['!','@']))
129
assert_equal([11,'Q','S',['!','@'],'a',22,33], a.insert(2, 'Q','S'))
130
end
131
132
def test_rindex()
133
a = [ "a", "b", "b", "b", "c" ]
134
a.base_index = 1
135
136
assert_equal(4, a.rindex("b"))
137
assert_equal(nil, a.rindex("z"))
138
end
139
140
def test_slice()
141
a = ['a','b','c','d','e']
142
a.base_index = 1
143
assert_equal(1, a.base_index)
144
assert_equal('a', a.slice(1))
145
assert_equal(['a','b','c'], a.slice(1,3))
146
assert_equal(['a','b','c','d'], a.slice(1..4))
147
assert_equal('e', a.slice(0))
148
assert_equal(nil, a.slice(6))
149
assert_equal([], a.slice(6,1))
150
assert_equal([], a.slice(6..10))
151
assert_equal(nil, a.slice(7,1))
152
end
153
154
def test_slice!()
155
a = ['a','b','c']
156
a.base_index = 1
157
158
assert_equal('b', a.slice!(2))
159
assert_equal(['a','c'], a)
160
assert_equal(nil, a.slice!(100))
161
assert_equal(['a','c'], a)
162
end
163
164
def test_indexes()
165
a = [11,22,33,44,55,66,77,88]
166
a.base_index = 1
167
168
assert_equal([11], a.indexes(1))
169
assert_equal([11,33], a.indexes(1,3))
170
assert_equal([11,11], a.indexes(1,1))
171
assert_equal([11,33,11], a.indexes(1,3,1))
172
assert_equal([[11,22,33],[22,33,44],77], a.indexes(1..3,2..4,7))
173
assert_equal([[11,22]], a.indexes(1
3))
174
assert_equal([[]], a.indexes(2..1))
175
assert_equal([], a.indexes())
176
assert_equal([nil,nil], a.indexes(99,97))
177
end
178
179
def test_indices()
180
a = [11,22,33,44,55,66,77,88]
181
a.base_index = 1
182
183
assert_equal([11], a.indices(1))
184
assert_equal([11,33], a.indices(1,3))
185
assert_equal([11,11], a.indices(1,1))
186
assert_equal([11,33,11], a.indices(1,3,1))
187
assert_equal([[11,22,33],[22,33,44],77], a.indices(1..3,2..4,7))
188
assert_equal([[11,22]], a.indices(1
3))
189
assert_equal([[]], a.indices(2..1))
190
assert_equal([], a.indices())
191
assert_equal([nil,nil], a.indices(99,97))
192
end
193
194
def test_values_at()
195
a = [11,22,33,44,55,66,77,88]
196
a.base_index = 1
197
198
assert_equal([11], a.values_at(1))
199
assert_equal([11,33], a.values_at(1,3))
200
assert_equal([11,11], a.values_at(1,1))
201
assert_equal([11,33,11], a.values_at(1,3,1))
202
assert_equal([11,22,33,22,33,44,77], a.values_at(1..3,2..4,7))
203
assert_equal([11,22], a.values_at(1
3))
204
assert_equal([], a.values_at(2..1))
205
assert_equal([], a.values_at())
206
assert_equal([nil,nil], a.values_at(99,97))
207
end
208
end