让Ruby的数组支持任意起始下标
2007-08-24 10:29
260 查看
我目前正在苦学《算法导论》。里面的堆排序算法是用数组表示一棵二叉树,就像这样
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()
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 (0 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
252end
单元测试代码(文件名“TestDynimicBaseIndex.rb”)
1require 'dynimic_base_index'
2require 'test/unit'
3
4class 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 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 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 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
208end
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()
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 (0 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
252end
单元测试代码(文件名“TestDynimicBaseIndex.rb”)
1require 'dynimic_base_index'
2require 'test/unit'
3
4class 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 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 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 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
208end
相关文章推荐
- 数组下标使用0起始的理由
- 数组中取出下标不连续的任意个数,求取出的数的和的最大值
- 简单介绍Ruby on Rails对PostgreSQL数组类型的支持
- ruby支持批量数组的定义
- 实现的任意下标开始的数组类
- 用PHP实现的快速排序算法(支持记录原始数组下标)
- PHP 获取数组任意下标key的上一个prev和下一个next下标值
- leetcode解题之303# Range Sum Query - Immutable Java版 (多次计算数组内任意两个下标之间的和)
- 利用数组下标实现从任意位置开始得循环
- Java面试题 - 使用二分法计算任意整数在任意整数数组中的下标,不存在则返回-1
- Ruby求出数组中最小值及其下标
- 微信小程序操作数组时,下标不支持变量的解决办法
- [算法]数组中求出下标不连续的任意个数,使得和最大
- 数组中取出下标不连续的任意个数,求取出的数的和的最大值
- 二分查找 基于有序数组 返回下标
- 分治算法求最大子数组以及其对应的下标<c/c++源代码>
- poj2479-在一个数组中求任意不相交的两个子数组之和的最大值
- 寻找数组的下标索引值index方法
- 通过随机数生成办法,向int num[10][10]的数组 中存入数据并找出数组的最大、最小值及其下标。
- 写代码可以在整型有序数组中查找想要的数字,找到了返回下标,找不到返回-1.(折半查找)