您的位置:首页 > 编程语言 > Ruby

让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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: