Module: Enumerable

Included in:
Instance, Tuple
Defined in:
lib/core/facets/enumerable/per.rb,
lib/core/facets/to_hash.rb,
lib/standard/facets/thread.rb,
lib/core/facets/enumerable/one.rb,
lib/core/facets/enumerable/sum.rb,
lib/core/facets/enumerable/none.rb,
lib/core/facets/enumerable/take.rb,
lib/core/facets/enumerable/count.rb,
lib/core/facets/enumerable/defer.rb,
lib/core/facets/enumerable/every.rb,
lib/core/facets/enumerable/ewise.rb,
lib/core/facets/enumerable/graph.rb,
lib/core/facets/enumerable/occur.rb,
lib/core/facets/enumerable/purge.rb,
lib/core/facets/enumerable/visit.rb,
lib/supplemental/facets/enumargs.rb,
lib/core/facets/enumerable/expand.rb,
lib/core/facets/enumerable/filter.rb,
lib/core/facets/enumerable/map_by.rb,
lib/core/facets/enumerable/each_by.rb,
lib/core/facets/enumerable/exclude.rb,
lib/core/facets/enumerable/uniq_by.rb,
lib/core/facets/enumerable/group_by.rb,
lib/core/facets/enumerable/map_send.rb,
lib/core/facets/enumerable/map_with.rb,
lib/core/facets/enumerable/modulate.rb,
lib/core/facets/enumerable/frequency.rb,
lib/core/facets/enumerable/accumulate.rb,
lib/core/facets/enumerable/cluster_by.rb,
lib/core/facets/enumerable/find_yield.rb,
lib/core/facets/enumerable/compact_map.rb,
lib/core/facets/enumerable/recursively.rb,
lib/core-uncommon/facets/enumerable/has.rb,
lib/core/facets/enumerable/map_with_index.rb,
lib/core/facets/enumerable/each_with_object.rb

Overview

This is a simple reimplementation of the core Enumerable module to allow the methods to take and pass-on arbitrary arguments to the underlying #each call. This library uses Enumerator and scans Enumerable so it can alwasy stay in sync.

NOTE Any Enumerable method with a negative arity cannot do pass arguments due to ambiguity in the argument count. So the methods #inject and #zip do NOT work this way, but simply work as they do in Enumerable. The method #find (and #detect) though has been made to work by removing its rarely used optional parameter and providing instead an optional keyword parameter (:ifnone => …). Please keep these difference in mind.

require 'enumargs'

class T
  include Enumerable::Arguments
  def initialize(arr)
    @arr = arr
  end
  def each(n)
    arr.each{ |e| yield(e+n) }
  end
end

t = T.new([1,2,3])
t.collect(4)
#=> [5,6,7]

Defined Under Namespace

Modules: Arguments Classes: Permeator, Recursor

Instance Method Summary collapse

Instance Method Details

#accumulate(iterations = 1) ⇒ Object

Accumulate a set of a set. For example, in an ORM design where ‘Group has_many User` we might have something equivalent to the following.

Group = Struct.new(:users)
User  = Struct.new(:name, :friends)

user1 = User.new('John', [])
user2 = User.new('Jane', ['Jill'])
user3 = User.new('Joe' , ['Jack', 'Jim'])

group1 = Group.new([user1, user2])
group2 = Group.new([user2, user3])

groups = [group1, group2]

Now we can accumulate the users of all groups.

groups.accumulate.users  #=> [user1, user2, user3]

You may pass an argument to perform chains, e.g. the following returns the names of users from all groups.

groups.accumulate(2).users.name  #=> ['John','Jane','Joe']

Or we can gather all the friends of all users in groups.

groups.accumulate(2).users.friends  #=> ['Jill','Jack','Jim']

This is more convenient then the equivalent.

groups.accumulate.users.accumulate.friends  #=> ['Jill','Jack','Jim']

CREDIT: George Moshchovitis, Daniel Emirikol



40
41
42
43
44
45
46
# File 'lib/core/facets/enumerable/accumulate.rb', line 40

def accumulate(iterations=1)
  return self if iterations == 0
  Functor.new do |op, *args|
    result = inject([]) { |a, x| a << x.send(op, *args) }.flatten.uniq
    result.accumulate(iterations - 1)
  end
end

#accumulate_all(iterations = 1) ⇒ Object

Same as #accumulate, but does not apply #uniq to final result.

groups.accumulate_all(2).users.friends  #=> ['Jill', 'Jill','Jack','Jim']


52
53
54
55
56
57
58
# File 'lib/core/facets/enumerable/accumulate.rb', line 52

def accumulate_all(iterations=1)
  return self if iterations == 0
  Functor.new do |op, *args|
    result = inject([]) { |a, x| a << x.send(op, *args) }.flatten
    result.accumulate_all(iterations - 1)
  end
end

#cluster_by(&b) ⇒ Object

Similar to #group_by but returns an array of the groups. Returned elements are sorted by block.

%w{this is a test}.cluster_by {|x| x[0]}
#=> [ ['a'], ['is'], ['this', 'test'] ]

CREDIT: Erik Veenstra



13
14
15
# File 'lib/core/facets/enumerable/cluster_by.rb', line 13

def cluster_by(&b)
  group_by(&b).sort.transpose.pop || []   # group_by(&b).values ?
end

#compact_map(&block) ⇒ Object Also known as: compact_collect

A more versitle #compact method. It can be used to collect and filter items out in one single step.

c = [1,2,3].compact_map do |n|
  n < 2 ? nil : n
end

c  #=> [2,3]

CREDIT: Trans

DEPRECATE: This method should probably be removed b/c #purge does almost the same thing and enum.map{}.compact works too.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/core/facets/enumerable/compact_map.rb', line 17

def compact_map(&block)
  y = []
  if block_given?
    each do |*a|
      r = yield(*a)
      y << r unless r.nil?
    end
  else
    each do |r|
      y << r unless r.nil?
    end
  end
  y
end

#count(*items, &block) ⇒ Object

Count the number of items in an enumerable equal (==) to the given object(s).

e = [ 'a', 1, 'a' ]

e.count(1)       #=> 1
e.count('a')     #=> 2

The method can count more than one item by supplying additional arguments.

e.count('a', 1)  #=> 3

A block may also be used to select countable entries.

e.count{ |x| String === x }  #=> 2

Note that Hash#count only considers values.

e = { 'a' => 2, 'x' => 2, 'b' => 1 }

e.count(1)  #=> 1
e.count(2)  #=> 2

NOTE: This is one of the few method overrides in Facets.

CREDIT: Trans



33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/core/facets/enumerable/count.rb', line 33

def count(*items, &block)
  if block || !items.empty?
    r = self
    r = r.select(&block) if block
    r = r.select{ |x| items.any?{ |i| i == x } } if !items.empty?
    r.size
  else
    begin
      size
    rescue
      i=0; each{ |e| i+=1 }; i
    end
  end
end

#defer(&blk) ⇒ Object

Without a block: wrap the Enumerable object in such a way that map, select and similar operations are performed “horizontally” across a series of blocks, instead of building an array of results at each step. This reduces memory usage, allows partial results to be provided early, and permits working with infinite series.

a = (1..1_000_000_000).defer.select{ |i| i % 2 == 0 }.
                             map{ |i| i + 100 }.
                             take(10).to_a

With a block: the block acts as an arbitrary filter on the data. Unlike map, it can choose to drop elements from the result, and/or add additional ones. The first object passed to the block is the receiver of the output.

(1..1_000_000_000).
  defer { |out,i| out << i if i % 2 == 0 }.  # like select
  defer { |out,i| out << i + 100 }.          # like map
  take(10).to_a

Use a method like to_a or to_h at the end of the chain when you want an Array or Hash built with the results, or each… if you just want to output each result and discard it.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/core/facets/enumerable/defer.rb', line 29

def defer(&blk)
  if block_given?
    Denumerator.new do |output|
      each do |*input|
        yield(output, *input)
      end
    end
  else
    Denumerator.new do |output|
      each do |*input|
        output.yield(*input)
      end
    end
  end
end

#each_by(steps = nil, &block) ⇒ Object

Iterate through slices. If slice steps is not given, the arity of the block is used.

x = []
[1,2,3,4].each_by{ |a,b| x << [a,b] }
x  #=> [ [1,2], [3,4] ]

x = []
[1,2,3,4,5,6].each_by(3){ |a| x << a }
x  #=> [ [1,2,3], [4,5,6] ]

This is just like each_slice, except that it will check the arity of the block. If each_slice ever suppots this this method can be deprecated.

CREDIT: Trans



22
23
24
25
26
27
28
29
30
# File 'lib/core/facets/enumerable/each_by.rb', line 22

def each_by(steps=nil, &block)
  if steps
    each_slice(steps, &block)
  else
    steps = block.arity.abs
    each_slice(steps, &block)
    #each_slice(steps) {|i| block.call(*i)}
  end
end

#each_with_object(memo) ⇒ Object

A variation of #inject that saves one from having to return the aggregate/memo argument.

Say we want to count characters in a string. Using the #each_with_object method we have:

"string".each_with_object(Hash.new(0)) do |c, h|
  h[c] += 1
end

versus using #inject which would be:

"string".inject(Hash.new(0)) do |h, c|
  h[c] +=1
  h
end

Notice that the order of the block parameters is reversed.

This method used be called #injecting and had the same parameter order as #inject, but Ruby 1.9 has adopted this method, so we support it instead.



28
29
30
31
32
33
# File 'lib/core/facets/enumerable/each_with_object.rb', line 28

def each_with_object(memo) #:yield:
  each do |element|
    yield(element, memo)
  end
  memo
end

#everyObject

Returns an elemental object. This allows you to map a method on to every element.

r = [1,2,3].every + 3
r  #=> [4,5,6]


11
12
13
# File 'lib/core/facets/enumerable/every.rb', line 11

def every
  per(:map)
end

#every!Object

In place version of #every.

Raises:

  • (NoMethodError)


17
18
19
20
# File 'lib/core/facets/enumerable/every.rb', line 17

def every!
  raise NoMethodError unless respond_to?(:map!)
  per(:map!)
end

#ewise(count = 1) ⇒ Object Also known as: elementwise

Returns an elementwise Functor designed to make R-like elementwise operations possible. This is very much like the #every method, but it treats array argument specially.

([1,2].ewise + 3)          #=> [4,5]

Vector to vector

([1,2].ewise + [4,5])      #=> [5,7]

Special thanks to Martin DeMello for helping to develop this.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/core/facets/enumerable/ewise.rb', line 17

def ewise(count=1)
  Functor.new do |op,*args|
    if args.empty?
      r = self
      count.times do
        r = r.collect{ |a| a.send(op) }
      end
      r
    else
      r = args.collect do |arg|
        if Array === arg #arg.kind_of?(Enumerable)
          x = self
          count.times do
            ln = (arg.length > length ? length : arg.length )
            x = x.slice(0...ln)
            x = x.zip(arg[0...ln])
            x = x.collect{ |a,b| a.send(op,b) }  #x = x.collect{ |a,b| b ? a.send(op,b) : nil }
          end
          x
        else
          x = self
          count.times do
            x = x.collect{ |a| a.send(op,arg) }
          end
          x
        end
      end
      r.flatten! if args.length == 1
      r
    end
  end
end

#exclude?(object) ⇒ Boolean

The inverse of #include?.

[:a, :b].exclude?(:c)  #=> true
[:a, :b].exclude?(:a)  #=> false

Returns:

  • (Boolean)


10
11
12
# File 'lib/core/facets/enumerable/exclude.rb', line 10

def exclude?(object)
  !include?(object)
end

#expandObject

Expand all elements of an Enumerable object.

[0, 2..3, 5..7].expand  #=> [0,[2, 3],[5,6,7]]

CREDIT: Trans



8
9
10
11
12
# File 'lib/core/facets/enumerable/expand.rb', line 8

def expand
  map do |x|
   (Enumerable === x ? x.expand : x)
  end
end

#filter(output = []) ⇒ Object

The block acts as an arbitrary filter on the data. Unlike map, it can choose to drop elements from the result and/or add additional elements. The first object passed to the block is the receiver of the output.

x = (1..10000)
x = x.filter{ |out,i| out << i if i % 2 == 0 }   # like select
x = x.filter{ |out,i| out << i + 100 }           # like map
x = x.take(3)

x  #=> [102, 104, 106]

This is very similar to #each_with_object, but #filter handles argument better by reversing their order and using the splat operator. (This was also once known as #injecting.)

CREDIT: David Black, Louis J Scoras



21
22
23
24
25
26
27
28
29
30
# File 'lib/core/facets/enumerable/filter.rb', line 21

def filter(output=[]) #:yeild:
  if block_given?
    each do |*input|
      yield(output, *input)
    end
    output
  else
    to_enum(:filter)
  end
end

#find_yield(fallback = nil) ⇒ Object Also known as: map_detect

Yield each element to the block and return the result of the block when that result evaluates as true, terminating early like #detect and #find.

obj1 = Object.new
obj2 = Object.new

def obj1.foo?; false; end
def obj2.foo?; true ; end

def obj1.foo ; "foo1"; end
def obj2.foo ; "foo2"; end

[obj1, obj2].find_yield{ |obj| obj.foo if obj.foo? }  #=> "foo2"

Another example.

[1,2,3,4,5].find_yield{ |i| j = i+1; j if j % 4 == 0 }  #=> 4

If the block is never true, return the object given in the first parameter, or nil if none specified.

[1,2,3].find_yield{ |_| false }    #=> nil
[false].find_yield(1){ |_| false } #=> 1


28
29
30
31
32
33
34
# File 'lib/core/facets/enumerable/find_yield.rb', line 28

def find_yield(fallback=nil) #:yield:
  each do |member|
    result = yield(member)
    return result if result 
  end
  fallback
end

#frequencyObject

Generates a hash mapping each unique symbol in the array to the absolute frequency it appears.

[:a,:a,:b,:c,:c,:c].frequency  #=> {:a=>2,:b=>1,:c=>3}

CREDIT: Brian Schröder

– NOTE: So why not use #inject here? e.g. …

inject(Hash.new(0)){|p,v| p[v]+=1; p}

Because it is a fair bit slower than the traditional definition. ++



18
19
20
21
# File 'lib/core/facets/enumerable/frequency.rb', line 18

def frequency
  p = Hash.new(0); each{ |v| p[v] += 1 }; p

end

#graph(&yld) ⇒ Object Also known as: mash

Like ‘#map`/`#collect`, but generates a Hash. The block is expected to return two values: the key and the value for the new hash.

numbers  = (1..3)
squares  = numbers.graph{ |n| [n, n*n] }   # { 1=>1, 2=>4, 3=>9 }
sq_roots = numbers.graph{ |n| [n*n, n] }   # { 1=>1, 4=>2, 9=>3 }

CREDIT: Andrew Dudzik (adudzik), Trans



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/core/facets/enumerable/graph.rb', line 12

def graph(&yld)
  if yld
    h = {}
    each do |*kv|
      r = yld[*kv]
      case r
      when Hash
        nk, nv = *r.to_a[0]
      when Range
        nk, nv = r.first, r.last
      else
        nk, nv = *r
      end
      h[nk] = nv
    end
    h
  else
    Enumerator.new(self,:graph)
  end
end

#group_byObject

Enumerable#group_by is used to group items in a collection by something they have in common. The common factor is the key in the resulting hash, the array of like elements is the value.

(1..5).group_by { |n| n % 3 }
#=> { 0 => [3], 1 => [1, 4], 2 => [2,5] }

Applied to an array.

["I had", 1, "dollar and", 50, "cents"].group_by { |e| e.class }
#=> { String => ["I had","dollar and","cents"], Fixnum => [1,50] }

Applied to a hash:

{:a=>1, :b=>2, :c=>1}.group_by{ |k,v| v }
#=> { 1=>[[:c,1], [:a,1]], 2=>[[:b,2]] }

CREDIT: Erik Veenstra



24
25
26
27
28
# File 'lib/core/facets/enumerable/group_by.rb', line 24

def group_by #:yield:
  r = Hash.new
  each{ |e| (r[yield(e)] ||= []) << e }
  r
end

#has?(what) ⇒ Boolean Also known as: have?

The same as #include?() but equality is tested using ===.

[1, 2, "a"].has?(2)       #=> true
[1, 2, "a"].has?(String)  #=> true
[1, 2, "a"].has?(3)       #=> false

NOTE: This is not (presently) a common core extension and is not loaded automatically when using require 'facets'.

TODO: Perhaps #matches? would be a better name?

CREDIT: Lavir the Whiolet

Returns:

  • (Boolean)


15
16
17
# File 'lib/core-uncommon/facets/enumerable/has.rb', line 15

def has?(what)
  any? { |x| what === x }
end

#map_byObject

Like #group_by, but maps the second value returned from the block.

a = [1,2,3,4,5]
a.map_by{ |e| [e % 2, e + 1] }
#=> { 0=>[3,5], 1=>[2,4,6] }

Works well with a hash too.

h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2}
h.map_by{ |k,v| [v, k.downcase] }
#=> {1=>["a", "b", "c"], 2=>["d", "e"]}

If a second value is not returned, #map_by acts like #group_by.

h = {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2}
h.map_by{ |k,v| v }
#=> {1=>[["A",1], ["B",1], ["C",1]], 2=>[["D",2], ["E",2]]}


21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/core/facets/enumerable/map_by.rb', line 21

def map_by #:yield:
  res = {}
  each do |a|
    k,v = yield(*a)
    if v
      (res[k] ||= []) << v
    else
      (res[k] ||= []) << a
    end
  end
  res
end

#map_send(meth, *args, &block) ⇒ Object

Send a message to each element and collect the result.

[1,2,3].map_send(:+, 3)  #=> [4,5,6]

CREDIT: Sean O’Halpin



9
10
11
# File 'lib/core/facets/enumerable/map_send.rb', line 9

def map_send(meth, *args, &block)
  map{|e| e.send(meth, *args, &block)}
end

#map_with(*arrays, &block) ⇒ Object Also known as: zip_map

Combines #zip and #map in a single efficient operation.

h = {}
[1,2,3].map_with [:x,:y,:z] do |n,k|
  h[k] = n
end
h  #=> {:x=>1, :y=>2, :z=>3}


11
12
13
# File 'lib/core/facets/enumerable/map_with.rb', line 11

def map_with(*arrays, &block)
  enum_for(:zip, *arrays).map(&block)
end

#map_with_indexObject Also known as: collect_with_index

Same as #collect but with an iteration counter.

a = [1,2,3].collect_with_index { |e,i| e*i }
a  #=> [0,2,6]

CREDIT: Gavin Sinclair



10
11
12
13
14
15
16
# File 'lib/core/facets/enumerable/map_with_index.rb', line 10

def map_with_index
  r = []
  each_with_index do |e, i|
    r << yield(e, i)
  end
  r
end

#modulate(modulo) ⇒ Object

Modulate. Divide an array into groups by modulo of the index.

[2,4,6,8].modulate(2)  #=> [[2,6],[4,8]]

CREDIT: Trans

NOTE: Would the better name for this be ‘collate’?

Raises:

  • (ArgumentError)


11
12
13
14
15
16
17
18
19
# File 'lib/core/facets/enumerable/modulate.rb', line 11

def modulate(modulo)
  return to_a if modulo == 1
  raise ArgumentError, 'bad modulo' if size % modulo != 0
  r = Array.new(modulo, [])
  (0...size).each do |i|
    r[i % modulo] += [self[i]]
  end
  r
end

#none?Boolean

Enumerable#none? is the logical opposite of the builtin method Enumerable#any?. It returns true if and only if none of the elements in the collection satisfy the predicate.

If no predicate is provided, Enumerable#none? returns true if and only if none of the elements have a true value (i.e. not nil or false).

[].none?                      # => true
[nil].none?                   # => true
[5,8,9].none?                 # => false
(1...10).none? { |n| n < 0 }  # => true
(1...10).none? { |n| n > 0 }  # => false

CREDIT: Gavin Sinclair

Returns:

  • (Boolean)


21
22
23
24
25
26
27
# File 'lib/core/facets/enumerable/none.rb', line 21

def none?  # :yield: e
  if block_given?
    not self.any? { |e| yield e }
  else
    not self.any?
  end
end

#occur(n = nil) ⇒ Object

Returns an array of elements for the elements that occur n times. Or according to the results of a given block.

a = [1,1,2,3,3,4,5,5]

a.occur(1).sort               #=> [2,4]
a.occur(2).sort               #=> [1,3,5]
a.occur(3).sort               #=> []

a.occur(1..1).sort            #=> [2,4]
a.occur(2..3).sort            #=> [1,3,5]

a.occur { |n| n == 1 }.sort   #=> [2,4]
a.occur { |n| n > 1 }.sort    #=> [1,3,5]


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/core/facets/enumerable/occur.rb', line 18

def occur(n=nil) #:yield:
  result = Hash.new { |hash, key| hash[key] = Array.new }
  self.each do |item|
    key = item
    result[key] << item
  end
  if block_given?
    result.reject! { |key, values| ! yield(values.size) }
  else
    raise ArgumentError unless n
    if Range === n
      result.reject! { |key, values| ! n.include?(values.size) }
    else
      result.reject! { |key, values| values.size != n }
    end
  end
  return result.values.flatten.uniq
end

#one?Boolean

Enumerable#one? returns true if and only if exactly one element in the collection satisfies the given predicate.

If no predicate is provided, Enumerable#one? returns true if and only if exactly one element has a true value (i.e. not nil or false).

[].one?                      # => false
[nil].one?                   # => false
[5].one?                     # => true
[5,8,9].one?                 # => false
(1...10).one? { |n| n == 5 } # => true
(1...10).one? { |n| n < 5 }  # => false

CREDIT: Gavin Sinclair

Returns:

  • (Boolean)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/core/facets/enumerable/one.rb', line 21

def one?  # :yield: e
  matches = 0
  if block_given?
    self.each do |e|
      if yield(e)
        matches += 1
        return false if matches > 1
      end
    end
    return (matches == 1)
  else
    one? { |e| e }
  end
end

#per(enum_method = nil, *enum_args) ⇒ Object

Per element meta-functor.

([1,2,3].per(:map) + 3)     #=> [4,5,6]
([1,2,3].per(:select) > 1)  #=> [2,3]

Using fluid notation.

([1,2,3].per.map + 3)       #=> [4,5,6]
([1,2,3].per.select > 1)    #=> [2,3]


19
20
21
22
23
24
25
26
27
# File 'lib/core/facets/enumerable/per.rb', line 19

def per(enum_method=nil, *enum_args)
  if enum_method
    Permeator.new(self, enum_method, *enum_args)
  else
    Functor.new do |enumr_method, *enumr_args|
      Permeator.new(self, enumr_method, *enumr_args)
    end
  end
end

#purge(*trash, &block) ⇒ Object

A versitle compaction method. Like #map but used to filter out multiple items in a single step.

Without trash arguments nil is assumed.

[1, nil, 2].purge  #=> [1,2]

If trash arguments are given, each argument is compared for a match using #==.

(1..6).purge(3,4)  #=> [1,2,5,6]

If a block is given, the yield is used in the matching condition instead of the element itsef.

(1..6).purge(0){ |n| n % 2 }  #=> [1,3,5]

NOTE: This could just as well be an override of the core #compact method, but to avoid potential issues associated with overriding core methods we use the alternate name #purge.

CREDIT: Trans



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/core/facets/enumerable/purge.rb', line 27

def purge(*trash, &block)
  trash = [nil] if trash.empty?
  r = []
  if block_given?
    each do |e|
      y = yield(e)
      r << e unless trash.any?{|t| t == y}
    end
  else
    each do |e|
      r << e unless trash.any?{|t| t == e}
    end
  end
  r
end

#recursively(*types, &block) ⇒ Object

Returns a recursive functor, that allows enumerable methods to iterate through enumerable sub-elements. By default it only recurses over elements of the same type.



7
8
9
# File 'lib/core/facets/enumerable/recursively.rb', line 7

def recursively(*types, &block)
  Recursor.new(self, *types, &block)
end

#sum(identity = 0, &block) ⇒ Object

Uses #+ to sum the enumerated elements.

[1,2,3].sum  #=> 6
[3,3,3].sum  #=> 9


8
9
10
11
12
13
14
# File 'lib/core/facets/enumerable/sum.rb', line 8

def sum(identity = 0, &block)
  if block_given?
    map(&block).sum
  else
    inject{ |sum, element| sum + element } || identity
  end
end

#take(n) ⇒ Object

Return the first n items from the collection



5
6
7
8
9
10
11
12
13
14
# File 'lib/core/facets/enumerable/take.rb', line 5

def take(n)
  res = []
  count = 0
  each do |e|
    break if count >= n
    res << e
    count += 1
  end
  res
end

#threaded_mapObject

Like Enumerable#map but each iteration is processed via a separate thread.

CREDIT: Sean O’Halpin



59
60
61
# File 'lib/standard/facets/thread.rb', line 59

def threaded_map #:yield:
  map{ |e| Thread.new(e){ |t| yield(t) } }.map{ |t| t.value }
end

#threaded_map_send(meth, *args, &block) ⇒ Object

Like Enumerable#map_send but each iteration is processed via a separate thread.

CREDIT: Sean O’Halpin



68
69
70
# File 'lib/standard/facets/thread.rb', line 68

def threaded_map_send(meth, *args, &block)
  map{ |e| Thread.new(e){ |t| t.send(meth, *args, &block) } }.map{ |t| t.value }
end

#to_h(mode = nil) ⇒ Object

Convert an Enumerable object into a hash by first turning it into an array.

CREDIT: Trans



227
228
229
# File 'lib/core/facets/to_hash.rb', line 227

def to_h(mode=nil)
  to_a.to_h(mode)
end

#to_h_assocObject



243
244
245
# File 'lib/core/facets/to_hash.rb', line 243

def to_h_assoc
  to_a.to_h_assoc
end

#to_h_autoObject



231
232
233
# File 'lib/core/facets/to_hash.rb', line 231

def to_h_auto
  to_a.to_h_auto
end

#to_h_flatObject



239
240
241
# File 'lib/core/facets/to_hash.rb', line 239

def to_h_flat
  to_a.to_h_flat
end

#to_h_multiObject



247
248
249
# File 'lib/core/facets/to_hash.rb', line 247

def to_h_multi
  to_a.to_h_multi
end

#to_h_splatObject



235
236
237
# File 'lib/core/facets/to_hash.rb', line 235

def to_h_splat
  to_a.to_h_splat
end

#uniq_byObject

Like #uniq, but determines uniqueness based on a given block.

(-5..5).to_a.uniq_by {|i| i*i }
#=> [-5, -4, -3, -2, -1, 0]


8
9
10
# File 'lib/core/facets/enumerable/uniq_by.rb', line 8

def uniq_by #:yield:
  h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x}
end

#visit(opts = {}, &block) ⇒ Object

Recursively iterate over all Enumerable elements, or subset given :type=>[type1, type2, …].

[1, 2, 8..9].visit{ |x| x.succ }
# => [2, 3, [9, 10]]


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/core/facets/enumerable/visit.rb', line 9

def visit(opts={}, &block)
  type = opts[:type] ? [opts[:type]].flatten : [Enumerable]
  skip = opts[:skip]

  map do |v|
    case v
    when String # b/c of 1.8
      block.call(v)
    when *type
      v.visit(opts, &block)
    else
      if skip && Enumerable === v
        v
      else
        block.call(v)
      end
    end
  end
end