improve Enumerable#reverse_each to be efficient
[mruby.git] / mrbgems / mruby-enum-ext / mrblib / enum.rb
blob0ce1d760558ae90d4967dfb89bee0ec7700f7a9a
1 ##
2 # Enumerable
4 module Enumerable
5   ##
6   # call-seq:
7   #    enum.drop(n)               -> array
8   #
9   # Drops first n elements from <i>enum</i>, and returns rest elements
10   # in an array.
11   #
12   #    a = [1, 2, 3, 4, 5, 0]
13   #    a.drop(3)             #=> [4, 5, 0]
15   def drop(n)
16     raise TypeError, "expected Integer for 1st argument" unless n.kind_of? Integer
17     raise ArgumentError, "attempt to drop negative size" if n < 0
19     ary = []
20     self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 }
21     ary
22   end
24   ##
25   # call-seq:
26   #    enum.drop_while {|arr| block }   -> array
27   #
28   # Drops elements up to, but not including, the first element for
29   # which the block returns +nil+ or +false+ and returns an array
30   # containing the remaining elements.
31   #
32   #    a = [1, 2, 3, 4, 5, 0]
33   #    a.drop_while {|i| i < 3 }   #=> [3, 4, 5, 0]
35   def drop_while(&block)
36     ary, state = [], false
37     self.each do |*val|
38       state = true if !state and !block.call(*val)
39       ary << val.__svalue if state
40     end
41     ary
42   end
44   ##
45   # call-seq:
46   #    enum.take(n)               -> array
47   #
48   # Returns first n elements from <i>enum</i>.
49   #
50   #    a = [1, 2, 3, 4, 5, 0]
51   #    a.take(3)             #=> [1, 2, 3]
53   def take(n)
54     raise TypeError, "expected Integer for 1st argument" unless n.kind_of? Integer
55     raise ArgumentError, "attempt to take negative size" if n < 0
57     ary = []
58     self.each do |*val|
59       break if ary.size >= n
60       ary << val.__svalue
61     end
62     ary
63   end
65   ##
66   # call-seq:
67   #    enum.take_while {|arr| block }   -> array
68   #
69   # Passes elements to the block until the block returns +nil+ or +false+,
70   # then stops iterating and returns an array of all prior elements.
71   #
72   #
73   #    a = [1, 2, 3, 4, 5, 0]
74   #    a.take_while {|i| i < 3 }   #=> [1, 2]
76   def take_while(&block)
77     ary = []
78     self.each do |*val|
79       return ary unless block.call(*val)
80       ary << val.__svalue
81     end
82     ary
83   end
84   
85   ##
86   # call-seq:
87   #   enum.each_cons(n) {...}   ->  nil
88   #
89   # Iterates the given block for each array of consecutive <n>
90   # elements.
91   #
92   # e.g.:
93   #     (1..10).each_cons(3) {|a| p a}
94   #     # outputs below
95   #     [1, 2, 3]
96   #     [2, 3, 4]
97   #     [3, 4, 5]
98   #     [4, 5, 6]
99   #     [5, 6, 7]
100   #     [6, 7, 8]
101   #     [7, 8, 9]
102   #     [8, 9, 10]
104   def each_cons(n, &block)
105     raise TypeError, "expected Integer for 1st argument" unless n.kind_of? Integer
106     raise ArgumentError, "invalid size" if n <= 0
108     ary = []
109     self.each do |*val|
110       ary.shift if ary.size == n
111       ary << val.__svalue
112       block.call(ary.dup) if ary.size == n
113     end
114   end
116   ##
117   # call-seq:
118   #   enum.each_slice(n) {...}  ->  nil
119   #
120   # Iterates the given block for each slice of <n> elements.
121   #
122   # e.g.:
123   #     (1..10).each_slice(3) {|a| p a}
124   #     # outputs below
125   #     [1, 2, 3]
126   #     [4, 5, 6]
127   #     [7, 8, 9]
128   #     [10]
130   def each_slice(n, &block)
131     raise TypeError, "expected Integer for 1st argument" unless n.kind_of? Integer
132     raise ArgumentError, "invalid slice size" if n <= 0
134     ary = []
135     self.each do |*val|
136       ary << val.__svalue
137       if ary.size == n
138         block.call(ary)
139         ary = []
140       end
141     end
142     block.call(ary) unless ary.empty?
143   end
145   ##
146   # call-seq:
147   #    enum.group_by {| obj | block }  -> a_hash
148   #
149   # Returns a hash, which keys are evaluated result from the
150   # block, and values are arrays of elements in <i>enum</i>
151   # corresponding to the key.
152   #
153   #    (1..6).group_by {|i| i%3}   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
155   def group_by(&block)
156     h = {}
157     self.each do |*val|
158       key = block.call(*val)
159       sv = val.__svalue
160       h.key?(key) ? (h[key] << sv) : (h[key] = [sv])
161     end
162     h
163   end
165   ##
166   # call-seq:
167   #    enum.sort_by { |obj| block }   -> array
168   #
169   # Sorts <i>enum</i> using a set of keys generated by mapping the
170   # values in <i>enum</i> through the given block.
171   def sort_by(&block)
172     ary = []
173     orig = [] 
174     self.each_with_index{|e, i|
175       orig.push(e)
176       ary.push([block.call(e), i])
177     }
178     if ary.size > 1
179       __sort_sub__(ary, ::Array.new(ary.size), 0, 0, ary.size - 1) do |a,b|
180         a <=> b
181       end
182     end
183     ary.collect{|e,i| orig[i]}
184   end
186   NONE = Object.new
187   ##
188   # call-seq:
189   #    enum.first       ->  obj or nil
190   #    enum.first(n)    ->  an_array
191   #
192   # Returns the first element, or the first +n+ elements, of the enumerable.
193   # If the enumerable is empty, the first form returns <code>nil</code>, and the
194   # second form returns an empty array.
195   def first(n=NONE)
196     if n == NONE
197       self.each do |*val|
198         return val.__svalue
199       end
200       return nil
201     else
202       a = []
203       i = 0
204       self.each do |*val|
205         break if n<=i
206         a.push val.__svalue
207         i += 1
208       end
209       a
210     end
211   end
213   ##
214   # call-seq:
215   #    enum.count                 -> int
216   #    enum.count(item)           -> int
217   #    enum.count { |obj| block } -> int
218   #
219   # Returns the number of items in +enum+ through enumeration.
220   # If an argument is given, the number of items in +enum+ that
221   # are equal to +item+ are counted.  If a block is given, it
222   # counts the number of elements yielding a true value.
223   def count(v=NONE, &block)
224     count = 0
225     if block
226       self.each do |*val|
227         count += 1 if block.call(*val)
228       end
229     else
230       if v == NONE
231         self.each { count += 1 }
232       else
233         self.each do |*val|
234           count += 1 if val.__svalue == v 
235         end
236       end
237     end
238     count
239   end
241   ##
242   # call-seq:
243   #    enum.flat_map       { |obj| block } -> array
244   #    enum.collect_concat { |obj| block } -> array
245   #    enum.flat_map                       -> an_enumerator
246   #    enum.collect_concat                 -> an_enumerator
247   #
248   # Returns a new array with the concatenated results of running
249   # <em>block</em> once for every element in <i>enum</i>.
250   #
251   # If no block is given, an enumerator is returned instead.
252   #
253   #    [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
254   #    [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]
255   def flat_map(&block)
256     return to_enum :flat_map unless block_given?
258     ary = []
259     self.each do |*e|
260       e2 = block.call(*e)
261       if e2.respond_to? :each
262         e2.each {|e3| ary.push(e3) }
263       else
264         ary.push(e2)
265       end
266     end
267     ary
268   end
269   alias collect_concat flat_map
271   ##
272   # call-seq:
273   #    enum.max_by {|obj| block }      -> obj
274   #    enum.max_by                     -> an_enumerator
275   #
276   # Returns the object in <i>enum</i> that gives the maximum
277   # value from the given block.
278   #
279   # If no block is given, an enumerator is returned instead.
280   #
281   #    %w[albatross dog horse].max_by {|x| x.length }   #=> "albatross"
283   def max_by(&block)
284     return to_enum :max_by unless block_given?
286     first = true
287     max = nil
288     max_cmp = nil
290     self.each do |*val|
291       if first
292         max = val.__svalue
293         max_cmp = block.call(*val)
294         first = false
295       else
296         if (cmp = block.call(*val)) > max_cmp
297           max = val.__svalue
298           max_cmp = cmp
299         end
300       end
301     end
302     max
303   end
305   ##
306   # call-seq:
307   #    enum.min_by {|obj| block }      -> obj
308   #    enum.min_by                     -> an_enumerator
309   #
310   # Returns the object in <i>enum</i> that gives the minimum
311   # value from the given block.
312   #
313   # If no block is given, an enumerator is returned instead.
314   #
315   #    %w[albatross dog horse].min_by {|x| x.length }   #=> "dog"
317   def min_by(&block)
318     return to_enum :min_by unless block_given?
320     first = true
321     min = nil
322     min_cmp = nil
324     self.each do |*val|
325       if first
326         min = val.__svalue
327         min_cmp = block.call(*val)
328         first = false
329       else
330         if (cmp = block.call(*val)) < min_cmp
331           min = val.__svalue
332           min_cmp = cmp
333         end
334       end
335     end
336     min
337   end
339   ##
340   #  call-seq:
341   #     enum.minmax                  -> [min, max]
342   #     enum.minmax { |a, b| block } -> [min, max]
343   #
344   #  Returns two elements array which contains the minimum and the
345   #  maximum value in the enumerable.  The first form assumes all
346   #  objects implement <code>Comparable</code>; the second uses the
347   #  block to return <em>a <=> b</em>.
348   #
349   #     a = %w(albatross dog horse)
350   #     a.minmax                                  #=> ["albatross", "horse"]
351   #     a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"]
353   def minmax(&block)
354     max = nil
355     min = nil
356     first = true
358     self.each do |*val|
359       if first
360         val = val.__svalue
361         max = val
362         min = val
363         first = false
364       else
365         if block
366           max = val.__svalue if block.call(*val, max) > 0
367           min = val.__svalue if block.call(*val, min) < 0
368         else
369           val = val.__svalue
370           max = val if (val <=> max) > 0
371           min = val if (val <=> min) < 0
372         end
373       end
374     end
375     [min, max]
376   end
378   ##
379   #  call-seq:
380   #     enum.minmax_by { |obj| block } -> [min, max]
381   #     enum.minmax_by                 -> an_enumerator
382   #
383   #  Returns a two element array containing the objects in
384   #  <i>enum</i> that correspond to the minimum and maximum values respectively
385   #  from the given block.
386   #
387   #  If no block is given, an enumerator is returned instead.
388   #
389   #     %w(albatross dog horse).minmax_by { |x| x.length }   #=> ["dog", "albatross"]
391   def minmax_by(&block)
392     max = nil
393     max_cmp = nil
394     min = nil
395     min_cmp = nil
396     first = true
398     self.each do |*val|
399       if first
400         max = min = val.__svalue
401         max_cmp = min_cmp = block.call(*val)
402         first = false
403      else
404         if (cmp = block.call(*val)) > max_cmp
405           max = val.__svalue
406           max_cmp = cmp
407         end
408         if (cmp = block.call(*val)) < min_cmp
409           min = val.__svalue
410           min_cmp = cmp
411         end
412       end
413     end
414     [min, max]
415   end
417   ##
418   #  call-seq:
419   #     enum.none? [{ |obj| block }]   -> true or false
420   #
421   #  Passes each element of the collection to the given block. The method
422   #  returns <code>true</code> if the block never returns <code>true</code>
423   #  for all elements. If the block is not given, <code>none?</code> will return
424   #  <code>true</code> only if none of the collection members is true.
425   #
426   #     %w(ant bear cat).none? { |word| word.length == 5 } #=> true
427   #     %w(ant bear cat).none? { |word| word.length >= 4 } #=> false
428   #     [].none?                                           #=> true
429   #     [nil, false].none?                                 #=> true
430   #     [nil, true].none?                                  #=> false
432   def none?(&block)
433     if block
434       self.each do |*val|
435         return false if block.call(*val)
436       end
437     else
438       self.each do |*val|
439         return false if val.__svalue
440       end
441     end
442     true
443   end
445   ##
446   #  call-seq:
447   #    enum.one? [{ |obj| block }]   -> true or false
448   #
449   # Passes each element of the collection to the given block. The method
450   # returns <code>true</code> if the block returns <code>true</code>
451   # exactly once. If the block is not given, <code>one?</code> will return
452   # <code>true</code> only if exactly one of the collection members is
453   # true.
454   #
455   #    %w(ant bear cat).one? { |word| word.length == 4 }  #=> true
456   #    %w(ant bear cat).one? { |word| word.length > 4 }   #=> false
457   #    %w(ant bear cat).one? { |word| word.length < 4 }   #=> false
458   #    [nil, true, 99].one?                               #=> false
459   #    [nil, true, false].one?                            #=> true
460   #
462   def one?(&block)
463     count = 0
464     if block
465       self.each do |*val|
466         count += 1 if block.call(*val)
467         return false if count > 1
468       end
469     else
470       self.each do |*val|
471         count += 1 if val.__svalue
472         return false if count > 1
473       end
474     end
476     count == 1 ? true : false
477   end
479   ##
480   #  call-seq:
481   #    enum.each_with_object(obj) { |(*args), memo_obj| ... }  ->  obj
482   #    enum.each_with_object(obj)                              ->  an_enumerator
483   #
484   #  Iterates the given block for each element with an arbitrary
485   #  object given, and returns the initially given object.
486   #
487   #  If no block is given, returns an enumerator.
488   #
489   #     (1..10).each_with_object([]) { |i, a| a << i*2 }
490   #     #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
491   #
493   def each_with_object(obj=nil, &block)
494     raise ArgumentError, "wrong number of arguments (0 for 1)" if obj == nil
496     return to_enum :each_with_object unless block_given?
498     self.each {|*val| block.call(val.__svalue, obj) }
499     obj
500   end
502   ##
503   #  call-seq:
504   #     enum.reverse_each { |item| block } ->  enum
505   #     enum.reverse_each                  ->  an_enumerator
506   #
507   #  Builds a temporary array and traverses that array in reverse order.
508   #
509   #  If no block is given, an enumerator is returned instead.
510   #
511   #      (1..3).reverse_each { |v| p v }
512   #
513   #    produces:
514   #
515   #      3
516   #      2
517   #      1
518   #
520   def reverse_each(&block)
521     ary = []
522     self.each {|*val| ary.push(val.__svalue) }
523     ary.reverse_each(&block)
524     self
525   end