1 # depends on: module.rb class.rb
4 # The Enumerable mixin provides collection classes with several traversal
5 # and searching methods, and with the ability to sort. The class must provide
6 # a method #each, which yields successive members of the collection. If
7 # Enumerable#max, #min, or #sort is used, the objects in the collection must
8 # also implement a meaningful <tt><=></tt> operator, as these methods rely on
9 # an ordering between members of the collection.
15 # Just to save you 10 seconds, the reason we always use #each to extract
16 # elements instead of something simpler is because Enumerable can not assume
17 # any other methods than #each. If needed, class-specific versions of any of
18 # these methods can be written *in those classes* to override these.
22 def initialize(sorter = nil)
27 # The ary should be inmutable while sorting
28 prc = Proc.new { |a,b| a <=> b } unless block_given?
31 @sorter = method(@sorter) unless @sorter.respond_to?(:call)
32 @sorter.call(xs, &prc)
38 alias_method :call, :sort
41 def initialize(val, sort_id)
42 @value, @sort_id = val, sort_id
49 @sort_id <=> other.sort_id
54 # The ary and its elements sould be inmutable while sorting
56 elements = xs.map { |x| SortedElement.new(x, yield(x)) }
57 sort(elements).map { |e| e.value }
61 # Sort an Enumerable using simple quicksort (not optimized)
63 def quicksort(xs, &prc)
67 xs.each { |o| pivot = o; break }
68 return xs if pivot.equal? Undefined
70 lmr = xs.group_by do |o|
78 quicksort(lmr[-1], &prc) + lmr[0] + quicksort(lmr[1], &prc)
86 # enum.entries => array
88 # Returns an array containing the items in +enum+.
90 # (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
91 # { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]]
97 alias_method :entries, :to_a
101 # enum.grep(pattern) => array
102 # enum.grep(pattern) { | obj | block } => array
104 # Returns an array of every element in +enum+ for which <tt>Pattern ===
105 # element</tt>. If the optional +block+ is supplied, each matching element
106 # is passed to it, and the block's result is stored in the output array.
108 # (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44]
110 # c.grep(/SEEK/) #=> ["SEEK_END", "SEEK_SET", "SEEK_CUR"]
111 # res = c.grep(/SEEK/) { |v| IO.const_get(v) }
118 ary << (block_given? ? yield(o) : o)
131 # enum.sort { | a, b | block } => array
133 # Returns an array containing the items in +enum+ sorted, either according
134 # to their own <tt><=></tt> method, or by using the results of the supplied
135 # block. The block should return -1, 0, or +1 depending on the comparison
136 # between +a+> and +b+. As of Ruby 1.8, the method Enumerable#sort_by
137 # implements a built-in Schwartzian Transform, useful when key computation
138 # or comparison is expensive..
140 # %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"]
141 # (1..10).sort { |a,b| b <=> a} #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
144 sorter.sort(self, &prc)
149 # enum.sort_by { | obj | block } => array
151 # Sorts +enum+ using a set of keys generated by mapping the
152 # values in +enum+ through the given block.
154 # %w{ apple pear fig }.sort_by { |word| word.length}
155 # #=> ["fig", "pear", "apple"]
157 # The current implementation of sort_by generates an array of tuples
158 # containing the original collection element and the mapped value. This makes
159 # sort_by fairly expensive when the keysets are simple
161 # require 'benchmark'
164 # a = (1..100000).map {rand(100000)}
167 # b.report("Sort") { a.sort }
168 # b.report("Sort by") { a.sort_by { |a| a} }
173 # user system total real
174 # Sort 0.180000 0.000000 0.180000 ( 0.175469)
175 # Sort by 1.980000 0.040000 2.020000 ( 2.013586)
177 # However, consider the case where comparing the keys is a non-trivial
178 # operation. The following code sorts some files on modification time
179 # using the basic sort method.
182 # sorted = files.sort { |a,b| File.new(a).mtime <=> File.new(b).mtime}
183 # sorted #=> ["mon", "tues", "wed", "thurs"]
185 # This sort is inefficient: it generates two new File objects during every
186 # comparison. A slightly better technique is to use the Kernel#test method
187 # to generate the modification times directly.
190 # sorted = files.sort { |a,b|
191 # test(?M, a) <=> test(?M, b)
193 # sorted #=> ["mon", "tues", "wed", "thurs"]
195 # This still generates many unnecessary Time objects. A more efficient
196 # technique is to cache the sort keys (modification times in this case)
197 # before the sort. Perl users often call this approach a Schwartzian
198 # Transform, after Randal Schwartz. We construct a temporary array, where
199 # each element is an array containing our sort key along with the filename.
200 # We sort this array, and then extract the filename from the result.
202 # sorted = Dir["#"].collect { |f|
204 # }.sort.collect { |f| f[1] }
205 # sorted #=> ["mon", "tues", "wed", "thurs"]
207 # This is exactly what sort_by does internally.
209 # sorted = Dir["#"].sort_by { |f| test(?M, f)}
210 # sorted #=> ["mon", "tues", "wed", "thurs"]
213 sorter.sort_by(self, &prc)
218 # enum.count(item) => int
219 # enum.count { | obj | block } => int
221 # Returns the number of items in +enum+ for which equals to +item+. If a
222 # block is given, counts the number of elements yielding a true value.
225 # ary.count(2) # => 2
226 # ary.count{ |x|x%2==0} # => 3
228 def count(item = Undefined)
230 unless item.equal? Undefined
231 each { |o| seq += 1 if item == o }
233 each { |o| seq += 1 if yield(o) }
240 # enum.detect(ifnone = nil) { | obj | block } => obj or nil
241 # enum.find(ifnone = nil) { | obj | block } => obj or nil
243 # Passes each entry in +enum+ to +block+>. Returns the first for which
244 # +block+ is not false. If no object matches, calls +ifnone+ and returns
245 # its result when it is specified, or returns nil
247 # (1..10).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
248 # (1..100).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> 35
250 def find(ifnone = nil)
251 each { |o| return o if yield(o) }
252 ifnone.call if ifnone
255 alias_method :detect, :find
259 # enum.find_index(ifnone = nil) { | obj | block } => int
261 # Passes each entry in +enum+ to +block+. Returns the index for the first
262 # for which +block+ is not false. If no object matches, returns
265 # (1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
266 # (1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 35
268 def find_index(ifnone = nil)
270 each { |o| idx += 1; return idx if yield(o) }
271 ifnone.call if ifnone
276 # enum.find_all { | obj | block } => array
277 # enum.select { | obj | block } => array
279 # Returns an array containing all elements of +enum+ for which +block+ is
280 # not false (see also Enumerable#reject).
282 # (1..10).find_all { |i| i % 3 == 0 } #=> [3, 6, 9]
294 alias_method :select, :find_all
298 # enum.reject { | obj | block } => array
300 # Returns an array for all elements of +enum+ for which +block+ is false
301 # (see also Enumerable#find_all).
303 # (1..10).reject { |i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10]
317 # enum.collect { | obj | block } => array
318 # enum.map { | obj | block } => array
320 # Returns a new array with the results of running +block+ once for every
323 # (1..4).collect { |i| i*i } #=> [1, 4, 9, 16]
324 # (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
329 each { |o| ary << yield(o) }
331 each { |o| ary << o }
336 alias_method :map, :collect
340 # enum.inject(initial) { | memo, obj | block } => obj
341 # enum.inject { | memo, obj | block } => obj
343 # Combines the elements of +enum+ by applying the block to an accumulator
344 # value (+memo+) and each element in turn. At each step, +memo+ is set
345 # to the value returned by the block. The first form lets you supply an
346 # initial value for +memo+. The second form uses the first element of the
347 # collection as a the initial value (and skips that element while
352 # (5..10).inject { |sum, n| sum + n } #=> 45
354 # Multiply some numbers:
356 # (5..10).inject(1) { |product, n| product * n } #=> 151200
358 # Find the longest word:
360 # longest = %w[ cat sheep bear ].inject do |memo,word|
361 # memo.length > word.length ? memo : word
364 # longest #=> "sheep"
366 # Find the length of the longest word:
368 # longest = %w[ cat sheep bear ].inject(0) do |memo,word|
369 # memo >= word.length ? memo : word.length
374 def inject(memo = Undefined)
376 if memo.equal? Undefined
379 memo = yield(memo, o)
383 memo.equal?(Undefined) ? nil : memo
388 # enum.partition { | obj | block } => [ true_array, false_array ]
390 # Returns two arrays, the first containing the elements of +enum+ for which
391 # the block evaluates to true, the second containing the rest.
393 # (1..6).partition { |i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]]
398 each { |o| yield(o) ? left.push(o) : right.push(o) }
404 # enum.group_by { | obj | block } => a_hash
406 # Returns a hash, which keys are evaluated result from the block, and values
407 # are arrays of elements in +enum+ corresponding to the key.
409 # (1..6).group_by { |i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
426 # enum.first => obj or nil
427 # enum.first(n) => an_array
429 # Returns the first element, or the first +n+ elements, of the enumerable.
430 # If the enumerable is empty, the first form returns nil, and the second
431 # form returns an empty array.
435 raise ArgumentError, "Invalid number of elements given."
440 return ary if ary.size == n
447 # enum.all? => true or false
448 # enum.all? { |obj| block } => true or false
450 # Passes each element of the collection to the given block. The method
451 # returns true if the block never returns false or nil. If the block is not
452 # given, Ruby adds an implicit block of <tt>{ |obj| obj }</tt> (that is all?
453 # will return true only if none of the collection members are
456 # %w[ant bear cat].all? { |word| word.length >= 3} #=> true
457 # %w[ant bear cat].all? { |word| word.length >= 4} #=> false
458 # [ nil, true, 99 ].all? #=> false
461 prc = Proc.new { |obj| obj } unless block_given?
462 each { |o| return false unless prc.call(o) }
468 # enum.any? [{ |obj| block } ] => true or false
470 # Passes each element of the collection to the given block. The method
471 # returns true if the block ever returns a value other than false or nil. If
472 # the block is not given, Ruby adds an implicit block of <tt>{ |obj| obj
473 # }</tt> (that is any? will return true if at least one of the collection
474 # members is not false or nil.
476 # %w[ant bear cat].any? { |word| word.length >= 3} #=> true
477 # %w[ant bear cat].any? { |word| word.length >= 4} #=> true
478 # [ nil, true, 99 ].any? #=> true
481 prc = Proc.new { |obj| obj } unless block_given?
482 each { |o| return true if prc.call(o) }
488 # enum.one? => true or false
489 # enum.one? { |obj| block } => true or false
491 # Passes each element of the collection to the given block. The method
492 # returns true if the block returns true exactly once. If the block is not
493 # given, one? will return true only if exactly one of the collection members
496 # %w[ant bear cat].one? { |word| word.length == 4} #=> true
497 # %w[ant bear cat].one? { |word| word.length >= 4} #=> false
498 # [ nil, true, 99 ].one? #=> true
501 prc = Proc.new { |obj| obj } unless block_given?
503 each { |o| times += 1 if prc.call(o) }
509 # enum.none? => true or false
510 # enum.none? { |obj| block } => true or false
512 # Passes each element of the collection to the given block. The method
513 # returns true if the block never returns true for all elements. If the
514 # block is not given, none? will return true only if any of the collection
517 # %w{ant bear cat}.none? { |word| word.length == 4} #=> true
518 # %w{ant bear cat}.none? { |word| word.length >= 4} #=> false
519 # [ nil, true, 99 ].none? #=> true
522 prc = Proc.new { |obj| obj } unless block_given?
524 each { |o| times += 1 if prc.call(o) }
531 # enum.min { | a,b | block } => obj
533 # Returns the object in +enum+ with the minimum value. The first form
534 # assumes all objects implement Comparable; the second uses the block to
535 # return <tt>a <=> b</tt>.
537 # a = %w[albatross dog horse]
538 # a.min #=> "albatross"
539 # a.min { |a,b| a.length <=> b.length } #=> "dog"
542 prc = Proc.new { |a, b| a <=> b } unless block_given?
545 if min.equal? Undefined
548 comp = prc.call(o, min)
550 raise ArgumentError, "comparison of #{o.class} with #{min} failed"
557 min.equal?(Undefined) ? nil : min
563 # enum.max { |a,b| block } => obj
565 # Returns the object in +enum+ with the maximum value. The first form
566 # assumes all objects implement Comparable; the second uses the block to
567 # return <tt>a <=> b</tt>.
569 # a = %w[albatross dog horse]
571 # a.max { |a,b| a.length <=> b.length } #=> "albatross"
574 prc = Proc.new { |a, b| a <=> b } unless block_given?
577 if max.equal? Undefined
580 comp = prc.call(o, max)
582 raise ArgumentError, "comparison of #{o.class} with #{max} failed"
589 max.equal?(Undefined) ? nil : max
594 # enum.min_by { |obj| block } => obj
596 # Uses the values returned by the given block as a substitute for the real
597 # object to determine what is considered the smallest object in +enum+ using
598 # <tt>lhs <=> rhs</tt>. In the event of a tie, the object that appears first
599 # in #each is chosen. Returns the "smallest" object or nil if the enum is
602 # a = %w[albatross dog horse]
603 # a.min_by { |x| x.length } #=> "dog"
606 min_obj, min_value = Undefined, Undefined
611 if min_obj.equal?(Undefined) or (min_value <=> value) > 0
612 min_obj, min_value = o, value
616 min_obj.equal?(Undefined) ? nil : min_obj
621 # enum.max_by { | obj| block } => obj
623 # Uses the values returned by the given block as a substitute for the real
624 # object to determine what is considered the largest object in +enum+ using
625 # <tt>lhs <=> rhs</tt>. In the event of a tie, the object that appears first
626 # in #each is chosen. Returns the "largest" object or nil if the enum is
629 # a = %w[albatross dog horse]
630 # a.max_by { |x| x.length } #=> "albatross"
633 max_obj, max_value = Undefined, Undefined
638 if max_obj.equal?(Undefined) or (max_value <=> value) < 0
639 max_obj, max_value = o, value
643 max_obj.equal?(Undefined) ? nil : max_obj
648 # enum.include?(obj) => true or false
649 # enum.member?(obj) => true or false
651 # Returns true if any member of +enum+ equals +obj+. Equality is tested
654 # IO.constants.include? "SEEK_SET" #=> true
655 # IO.constants.include? "SEEK_NO_FURTHER" #=> false
658 each { |o| return true if obj == o }
662 alias_method :member?, :include?
666 # enum.each_with_index { |obj, i| block } -> enum
668 # Calls +block+ with two arguments, the item and its index, for
669 # each item in +enum+.
672 # %w[cat dog wombat].each_with_index { |item, index|
676 # p hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
680 each { |o| yield(o, idx); idx += 1 }
686 # enum.zip(arg, ...) => array
687 # enum.zip(arg, ...) { |arr| block } => nil
689 # Converts any arguments to arrays, then merges elements of +enum+ with
690 # corresponding elements from each argument. This generates a sequence of
691 # enum#size +n+-element arrays, where +n+ is one more that the count of
692 # arguments. If the size of any argument is less than enum#size, nil values
693 # are supplied. If a block given, it is invoked for each output array,
694 # otherwise an array of arrays is returned.
699 # (1..3).zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
700 # "cat\ndog".zip([1]) #=> [["cat\n", 1], ["dog", nil]]
701 # (1..3).zip #=> [[1], [2], [3]]
705 args = args.map { |a| a.to_a }
706 each_with_index do |o, i|
707 result << args.inject([o]) { |ary, a| ary << a[i] }
708 yield(result.last) if block_given?
710 result unless block_given?