Fix method name
[mruby.git] / mrbgems / mruby-array-ext / mrblib / array.rb
blob2e66c5fbc9dc7e930f147bf8d3053dbc05c9a2c7
1 class Array
2   ##
3   # call-seq:
4   #    ary.uniq! -> ary or nil
5   #
6   # Removes duplicate elements from +self+.
7   # Returns <code>nil</code> if no changes are made (that is, no
8   # duplicates are found).
9   #
10   #    a = [ "a", "a", "b", "b", "c" ]
11   #    a.uniq!   #=> ["a", "b", "c"]
12   #    b = [ "a", "b", "c" ]
13   #    b.uniq!   #=> nil
14   #
15   def uniq!
16     ary = self.dup
17     result = []
18     while ary.size > 0
19       result << ary.shift
20       ary.delete(result.last)
21     end
22     if result.size == self.size
23       nil
24     else
25       self.replace(result)
26     end
27   end
29   ##
30   # call-seq:
31   #    ary.uniq   -> new_ary
32   #
33   # Returns a new array by removing duplicate values in +self+.
34   #
35   #    a = [ "a", "a", "b", "b", "c" ]
36   #    a.uniq   #=> ["a", "b", "c"]
37   #
38   def uniq
39     ary = self.dup
40     ary.uniq!
41     ary
42   end
44   ##
45   # call-seq:
46   #    ary - other_ary    -> new_ary
47   #
48   # Array Difference---Returns a new array that is a copy of
49   # the original array, removing any items that also appear in
50   # <i>other_ary</i>. (If you need set-like behavior, see the
51   # library class Set.)
52   #
53   #    [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]
54   #
55   def -(elem)
56     raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
58     hash = {}
59     array = []
60     elem.each { |x| hash[x] = true }
61     self.each { |x| array << x unless hash[x] }
62     array
63   end
65   ##
66   # call-seq:
67   #    ary | other_ary     -> new_ary
68   #
69   # Set Union---Returns a new array by joining this array with
70   # <i>other_ary</i>, removing duplicates.
71   #
72   #    [ "a", "b", "c" ] | [ "c", "d", "a" ]
73   #           #=> [ "a", "b", "c", "d" ]
74   #
75   def |(elem)
76     raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
78     ary = self + elem
79     ary.uniq! or ary
80   end
82   ##
83   # call-seq:
84   #    ary & other_ary      -> new_ary
85   #
86   # Set Intersection---Returns a new array
87   # containing elements common to the two arrays, with no duplicates.
88   #
89   #    [ 1, 1, 3, 5 ] & [ 1, 2, 3 ]   #=> [ 1, 3 ]
90   #
91   def &(elem)
92     raise TypeError, "can't convert #{elem.class} into Array" unless elem.class == Array
94     hash = {}
95     array = []
96     elem.each{|v| hash[v] = true }
97     self.each do |v|
98       if hash[v]
99         array << v
100         hash.delete v
101       end
102     end
103     array
104   end
106   ##
107   # call-seq:
108   #    ary.flatten -> new_ary
109   #    ary.flatten(level) -> new_ary
110   #
111   # Returns a new array that is a one-dimensional flattening of this
112   # array (recursively). That is, for every element that is an array,
113   # extract its elements into the new array.  If the optional
114   # <i>level</i> argument determines the level of recursion to flatten.
115   #
116   #    s = [ 1, 2, 3 ]           #=> [1, 2, 3]
117   #    t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
118   #    a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
119   #    a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
120   #    a = [ 1, 2, [3, [4, 5] ] ]
121   #    a.flatten(1)              #=> [1, 2, 3, [4, 5]]
122   #
123   def flatten(depth=nil)
124     ar = []
125     self.each do |e|
126       if e.is_a?(Array) && (depth.nil? || depth > 0)
127         ar += e.flatten(depth.nil? ? nil : depth - 1)
128       else
129         ar << e
130       end
131     end
132     ar
133   end
135   ##
136   # call-seq:
137   #    ary.flatten!        -> ary or nil
138   #    ary.flatten!(level) -> array or nil
139   #
140   # Flattens +self+ in place.
141   # Returns <code>nil</code> if no modifications were made (i.e.,
142   # <i>ary</i> contains no subarrays.)  If the optional <i>level</i>
143   # argument determines the level of recursion to flatten.
144   #
145   #    a = [ 1, 2, [3, [4, 5] ] ]
146   #    a.flatten!   #=> [1, 2, 3, 4, 5]
147   #    a.flatten!   #=> nil
148   #    a            #=> [1, 2, 3, 4, 5]
149   #    a = [ 1, 2, [3, [4, 5] ] ]
150   #    a.flatten!(1) #=> [1, 2, 3, [4, 5]]
151   #
152   def flatten!(depth=nil)
153     modified = false
154     ar = []
155     self.each do |e|
156       if e.is_a?(Array) && (depth.nil? || depth > 0)
157         ar += e.flatten(depth.nil? ? nil : depth - 1)
158         modified = true
159       else
160         ar << e
161       end
162     end
163     if modified
164       self.replace(ar)
165     else
166       nil
167     end
168   end
170   ##
171   # call-seq:
172   #    ary.compact     -> new_ary
173   #
174   # Returns a copy of +self+ with all +nil+ elements removed.
175   #
176   #    [ "a", nil, "b", nil, "c", nil ].compact
177   #                      #=> [ "a", "b", "c" ]
178   #
179   def compact
180     result = self.dup
181     result.compact!
182     result
183   end
185   ##
186   # call-seq:
187   #    ary.compact!    -> ary  or  nil
188   #
189   # Removes +nil+ elements from the array.
190   # Returns +nil+ if no changes were made, otherwise returns
191   # <i>ary</i>.
192   #
193   #    [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
194   #    [ "a", "b", "c" ].compact!           #=> nil
195   #
196   def compact!
197     result = self.select { |e| e != nil }
198     if result.size == self.size
199       nil
200     else
201       self.replace(result)
202     end
203   end
205   # for efficiency
206   def reverse_each(&block)
207     return to_enum :reverse_each unless block_given?
209     i = self.size - 1
210     while i>=0
211       block.call(self[i])
212       i -= 1
213     end
214     self
215   end
217   NONE=Object.new
218   ##
219   #  call-seq:
220   #     ary.fetch(index)                    -> obj
221   #     ary.fetch(index, default)           -> obj
222   #     ary.fetch(index) { |index| block }  -> obj
223   #
224   #  Tries to return the element at position +index+, but throws an IndexError
225   #  exception if the referenced +index+ lies outside of the array bounds.  This
226   #  error can be prevented by supplying a second argument, which will act as a
227   #  +default+ value.
228   #
229   #  Alternatively, if a block is given it will only be executed when an
230   #  invalid +index+ is referenced.  Negative values of +index+ count from the
231   #  end of the array.
232   #
233   #     a = [ 11, 22, 33, 44 ]
234   #     a.fetch(1)               #=> 22
235   #     a.fetch(-1)              #=> 44
236   #     a.fetch(4, 'cat')        #=> "cat"
237   #     a.fetch(100) { |i| puts "#{i} is out of bounds" }
238   #                              #=> "100 is out of bounds"
239   #
241   def fetch(n=nil, ifnone=NONE, &block)
242     warn "block supersedes default value argument" if n != nil && ifnone != NONE && block
244     idx = n
245     if idx < 0
246       idx += size
247     end
248     if idx < 0 || size <= idx
249       return block.call(n) if block
250       if ifnone == NONE
251         raise IndexError, "index #{n} outside of array bounds: #{-size}...#{size}"
252       end
253       return ifnone
254     end
255     self[idx]
256   end
258   ##
259   #  call-seq:
260   #     ary.fill(obj)                                 -> ary
261   #     ary.fill(obj, start [, length])               -> ary
262   #     ary.fill(obj, range )                         -> ary
263   #     ary.fill { |index| block }                    -> ary
264   #     ary.fill(start [, length] ) { |index| block } -> ary
265   #     ary.fill(range) { |index| block }             -> ary
266   #
267   #  The first three forms set the selected elements of +self+ (which
268   #  may be the entire array) to +obj+.
269   #
270   #  A +start+ of +nil+ is equivalent to zero.
271   #
272   #  A +length+ of +nil+ is equivalent to the length of the array.
273   #
274   #  The last three forms fill the array with the value of the given block,
275   #  which is passed the absolute index of each element to be filled.
276   #
277   #  Negative values of +start+ count from the end of the array, where +-1+ is
278   #  the last element.
279   #
280   #     a = [ "a", "b", "c", "d" ]
281   #     a.fill("x")              #=> ["x", "x", "x", "x"]
282   #     a.fill("w", -1)          #=> ["x", "x", "x", "w"]
283   #     a.fill("z", 2, 2)        #=> ["x", "x", "z", "z"]
284   #     a.fill("y", 0..1)        #=> ["y", "y", "z", "z"]
285   #     a.fill { |i| i*i }       #=> [0, 1, 4, 9]
286   #     a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27]
287   #     a.fill(1, 2) { |i| i+1 } #=> [0, 2, 3, 27]
288   #     a.fill(0..1) { |i| i+1 } #=> [1, 2, 3, 27]
289   #
291   def fill(arg0=nil, arg1=nil, arg2=nil, &block)
292     if arg0 == nil && arg1 == nil && arg2 == nil && !block
293       raise ArgumentError, "wrong number of arguments (0 for 1..3)" 
294     end
296     beg = len = 0
297     ary = []
298     if block
299       if arg0 == nil && arg1 == nil && arg2 == nil
300         # ary.fill { |index| block }                    -> ary
301         beg = 0
302         len = self.size
303       elsif arg0 != nil && arg0.respond_to?(:begin) && arg0.respond_to?(:end)
304         # ary.fill(range) { |index| block }             -> ary
305         beg = arg0.begin
306         beg += self.size if beg < 0
307         len = arg0.end - beg + 1
308       elsif arg0 != nil
309         # ary.fill(start [, length] ) { |index| block } -> ary
310         beg = arg0
311         beg += self.size if beg < 0
312         if arg1 == nil
313           len = self.size
314         else
315           len = arg0 + arg1
316         end
317       end
318     else
319       if arg0 != nil && arg1 == nil && arg2 == nil
320         # ary.fill(obj)                                 -> ary
321         beg = 0
322         len = self.size      
323       elsif arg0 != nil && arg1 != nil && arg1.respond_to?(:begin) && arg1.respond_to?(:end)
324         # ary.fill(obj, range )                         -> ary
325         len = self.size
326         beg = arg1.begin
327         len = arg1.end - beg + 1
328       elsif arg0 != nil && arg1 != nil
329         # ary.fill(obj, start [, length])               -> ary
330         beg = arg1
331         beg += self.size if beg < 0
332        if arg2 == nil
333           len = self.size
334         else
335           len = arg1 + arg2
336         end
337       end
338     end
340     i = beg
341     if block
342       while i < len
343         self[i] = block.call(i)
344         i += 1
345       end
346     else 
347       while i < len
348         self[i] = arg0
349         i += 1
350       end
351     end
352     self
353   end