Module Enumerable
In: lib/core/facets/to_hash.rb
lib/core/facets/enumerable/take.rb
lib/core/facets/enumerable/one.rb
lib/core/facets/enumerable/cluster_by.rb
lib/core/facets/enumerable/group_by.rb
lib/core/facets/enumerable/sum.rb
lib/core/facets/enumerable/mode.rb
lib/core/facets/enumerable/commonality.rb
lib/core/facets/enumerable/occur.rb
lib/core/facets/enumerable/frequency.rb
lib/core/facets/enumerable/divide.rb
lib/core/facets/enumerable/inject.rb
lib/core/facets/enumerable/duplicates.rb
lib/core/facets/enumerable/none.rb
lib/core/facets/enumerable/uniq_by.rb
lib/core/facets/enumerable/accumulate.rb
lib/core/facets/enumerable/mash.rb
lib/core/facets/enumerable/modulate.rb
lib/core/facets/enumerable/entropy.rb
lib/core/facets/enumerable/split.rb
lib/core/facets/enumerable/map_send.rb
lib/core/facets/enumerable/probability.rb
lib/core/facets/enumerable/map_with_index.rb
lib/core/facets/enumerable/count.rb
lib/core/facets/enumerable/each_by.rb
lib/core/facets/enumerable/compact_map.rb
lib/lore/facets/enumerator.rb
lib/more/facets/thread.rb
lib/more/facets/elementwise.rb
lib/more/facets/filter.rb
lib/more/facets/elementor.rb

Methods

Classes and Modules

Module Enumerable::Filterable
Class Enumerable::Elementor
Class Enumerable::Enumerator

Public Instance methods

Accumulate a set of a set.

For example, in an ORM design if Group has_many User then

  groups.accumulate.users

will return a list of users from all groups.

CREDIT: George Moshchovitis

[Source]

# File lib/core/facets/enumerable/accumulate.rb, line 16
  def accumulate
    @_accumulate ||= Functor.new do |op, *args|
      inject([]) { |a, x| a << x.send(op, *args) }.flatten
    end
  end

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]}

produces

   [ ['a'], ['is'], ['this', 'test'] ]

CREDIT: Erik Veenstra

[Source]

# File lib/core/facets/enumerable/cluster_by.rb, line 16
  def cluster_by(&b)
    group_by(&b).sort.transpose.pop || []   # group_by(&b).values ?
  end
collect_with_index()

Alias for map_with_index

Returns all items that are equal in terms of the supplied block. If no block is given objects are considered to be equal if they return the same value for Object#hash and if obj1 == obj2.

  [1, 2, 2, 3, 4, 4].commonality # => { 2 => [2], 4 => [4] }

  ["foo", "bar", "a"].commonality { |str| str.length }
  # => { 3 => ["foo, "bar"] }

  # Returns all persons that share their last name with another person.
  persons.collisions { |person| person.last_name }

CREDIT: Florian Gross

[Source]

# File lib/core/facets/enumerable/commonality.rb, line 17
  def commonality( &block )
    had_no_block = !block
    block ||= lambda { |item| item }
    result = Hash.new { |hash, key| hash[key] = Array.new }
    self.each do |item|
      key = block.call(item)
      result[key] << item
    end
    result.reject! do |key, values|
      values.size <= 1
    end
    #return had_no_block ? result.values.flatten : result
    return result
  end
compact_collect(trash=nil, &block)

Alias for compact_map

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

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

produces

  [2,3]

NOTE: Perhaps nicer to have as added functionality for compact.

CREDIT: Trans

[Source]

# File lib/core/facets/enumerable/compact_map.rb, line 18
  def compact_map(trash=nil, &block)
    y = []
    if block_given?
      each do |*a|
        r = yield(*a)
        y << r unless trash == r
      end
    else
      each do |r|
        y << r unless trash == r
      end
    end
    y
  end

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

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

Count can also handle multiple-valued blocks.

  e = { 'a' => 2, 'a' => 2, 'b' => 1 }
  e.count('a',2)  #=> 1

CREDIT: Trans

[Source]

# File lib/core/facets/enumerable/count.rb, line 19
    def count(*c)
      self.select{ |*i| i == c }.length
    end

Divide on matching pattern.

  ['a1','b1','a2','b2'].divide(/^a/)
  => [['a1,'b1'],['a2','b2']]

CREDIT: Trans

[Source]

# File lib/core/facets/enumerable/divide.rb, line 10
  def divide(pattern)
    memo = []
    each do |obj|
      memo.push [] if pattern === obj
      memo.last << obj
    end
    memo
  end
duplicates()

Alias for nonuniq

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

[Source]

# 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
elements()

Alias for every

elements!()

Alias for every!

Returns an elementwise Functor designed to make R-like elementwise operations possible.

  [1,2].elementwise + 3          #=> [4,5]
  [1,2].elementwise + [4,5]      #=> [5,7]
  [1,2].elementwise + [[4,5],3]  #=> [[5,7],[4,5]

[Source]

# File lib/more/facets/elementwise.rb, line 16
  def elementwise(count=1)
    @_elementwise_functor ||= []
    @_elementwise_functor[count] ||= 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).zip(arg[0...ln]).collect{ |a,b| a.send(op,b) }
              #slice(0...ln).zip(arg[0...1n]).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

Shannon‘s entropy for an array - returns the average bits per symbol required to encode the array. Lower values mean less "entropy" - i.e. less unique information in the array.

  %w{ a b c d e e e }.entropy  #=>

CREDIT: Derek

[Source]

# File lib/core/facets/enumerable/entropy.rb, line 14
  def entropy
    arr = to_a
    probHash = arr.probability
    # h is the Shannon entropy of the array
    h = -1.to_f * probHash.keys.inject(0.to_f) do |sum, i|
      sum + (probHash[i] * (Math.log(probHash[i])/Math.log(2.to_f)))
    end
    h
  end

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

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

[Source]

# File lib/more/facets/elementor.rb, line 57
  def every
    @_every ||= to_elem
  end

In place version of every.

[Source]

# File lib/more/facets/elementor.rb, line 63
  def every!
    raise NoMethodError unless respond_to?(:map!)
    @_every_inplace ||= to_elem(:map!)
  end
ewise(count=1)

Alias for elementwise

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.

  (1..1_000_000_000).filter.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).
    filter { |out,i| out << i if i % 2 == 0 }.  # like select
    filter { |out,i| out << i + 100 }.          # like map
    take(10).each { |i| puts i }

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

[Source]

# File lib/more/facets/filter.rb, line 30
  def filter(&blk)
    if block_given?
      Enumerator::Filter.new do |output|
        each do |*input|
          yield output, *input
        end
      end
    else
      Enumerator::Filter.new do |output|
        each do |*input|
          output.yield *input
        end
      end
    end
  end

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

CREDIT: Brian Schröder

[Source]

# File lib/core/facets/enumerable/frequency.rb, line 8
  def frequency
    #probs = Hash.new(0)
    #each do |e|
    #  probs[e] += 1
    #end
    #probs
    inject(Hash.new(0)){|h,v| h[v]+=1; h}
  end
graph(&yld)

Alias for mash

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] }

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

CREDIT: Erik Veenstra

[Source]

# File lib/core/facets/enumerable/group_by.rb, line 17
    def group_by #:yield:
      #h = k = e = nil
      r = Hash.new
      each{ |e| (r[yield(e)] ||= []) << e }
      r
    end

Returns the maximum possible Shannon entropy of the array with given size assuming that it is an "order-0" source (each element is selected independently of the next).

CREDIT: Derek

[Source]

# File lib/core/facets/enumerable/entropy.rb, line 30
  def ideal_entropy
    arr = to_a
    unitProb = 1.0.to_f / arr.size.to_f
    (-1.to_f * arr.size.to_f * unitProb * Math.log(unitProb)/Math.log(2.to_f))
  end

A small variation of Inject that save one from having to return the aggregating or memo argument.

Say you want to count letters.

   some_text.inject!(Hash.new(0)) {|h,l| h[l] += 1}

vs

   some_text.inject(Hash.new(0)) {|h,l| h[l] +=1; h}

CREDIT: David Black, Louis J Scoras

[Source]

# File lib/core/facets/enumerable/inject.rb, line 16
  def inject!(s)
    k = s
    each { |i| yield(k, i) }
    k
  end

Send a message to each element and collect the result.

CREDIT: Sean O‘Halpin

[Source]

# File lib/core/facets/enumerable/map_send.rb, line 7
  def map_send(meth, *args, &block)
    map{|e| e.send(meth, *args, &block)}
  end

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

[Source]

# File lib/core/facets/enumerable/map_with_index.rb, line 10
  def map_with_index
    r = []
    each_index do |i|
      r << yield(self[i], i)
    end
    r
  end

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.mash { |n| [n, n*n] }   # { 1=>1, 2=>4, 3=>9 }
  sq_roots = numbers.mash { |n| [n*n, n] }   # { 1=>1, 4=>2, 9=>3 }

The name "mash" stands for "map hash".

CREDIT: Andrew Dudzik (adudzik), Trans

[Source]

# File lib/core/facets/enumerable/mash.rb, line 14
  def mash(&yld)
    if yld
      inject({}) do |h, *kv| # Used to be inject({}) do |h,kv|
        r = *yld[*kv]        # The *-op works differnt from to_a on single element hash!!!
        nk, nv = *r          # Used to be nk, nv = *yld[*kv].to_a.flatten
        h[nk] = nv
        h
      end
    else
      Enumerator.new(self,:graph)  # Used to be Hash[*self.to_a] or Hash[*self.to_a.flatten]
    end
  end

In Statistics mode is the value that occurs most frequently in a given set of data.

CREDIT: Robert Klemme

[Source]

# File lib/core/facets/enumerable/mode.rb, line 8
  def mode
    max = 0
    c = Hash.new 0
    each {|x| cc = c[x] += 1; max = cc if cc > max}
    c.select {|k,v| v == max}.map {|k,v| k}
  end

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’?

[Source]

# 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

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

[Source]

# 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

Returns a list on non-unique,

  [1,1,2,2,3,4,5].nonuniq  #=> [1,2]

CREDIT: Martin DeMello

[Source]

# File lib/core/facets/enumerable/duplicates.rb, line 9
  def nonuniq
    h1 = {}
    h2 = {}
    each {|i|
      h2[i] = true if h1[i]
      h1[i] = true
    }
    h2.keys
  end

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

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

  [1,2,2,3,3,3].occur(1..1)              #=> [1]
  [1,2,2,3,3,3].occur(2..3)              #=> [2,3]

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

[Source]

# File lib/core/facets/enumerable/occur.rb, line 16
  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

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

[Source]

# 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

[Source]

# File lib/more/facets/elementor.rb, line 46
  def per
    @__per__ ||= Functor.new do |op|
      Elementor.new(self, op)
    end
  end

Generates a hash mapping each unique element in the array to the relative frequency, i.e. the probablity, of it appearence.

CREDIT: Brian Schröder

[Source]

# File lib/core/facets/enumerable/probability.rb, line 9
  def probability
    probs = Hash.new(0.0)
    size = 0.0
    each do | e |
      probs[e] += 1.0
      size += 1.0
    end
    probs.keys.each{ |e| probs[e] /= size }
    probs
  end

Split on matching pattern. Unlike divide this does not include matching elements.

  ['a1','a2','b1','a3','b2','a4'].split(/^b/)
  => [['a1','a2'],['a3'],['a4']]

CREDIT: Trans

[Source]

# File lib/core/facets/enumerable/split.rb, line 10
  def split(pattern)
    memo = []
    sect = []
    each do |obj|
      if pattern === obj
        memo << sect
        sect = []
      else
        sect << obj
      end
    end
    memo << sect
    memo.pop while memo.last == []
    memo
  end

Uses #+ to sum the enumerated elements.

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

[Source]

# 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

Return the first n items from the collection

[Source]

# File lib/core/facets/enumerable/take.rb, line 7
    def take(n)
      res = []
      count = 0
      each do |e|
        break if count >= n
        res << e
        count += 1
      end
      res
    end

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

CREDIT Sean O‘Halpin

[Source]

# File lib/more/facets/thread.rb, line 37
  def threaded_map #:yield:
    map{ |e| Thread.new(e){ |t| yield(t) } }.map{ |t| t.value }
  end

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

CREDIT Sean O‘Halpin

[Source]

# File lib/more/facets/thread.rb, line 46
  def threaded_map_send(meth, *args, &block)
    map{ |e| Thread.new(e){ |t| t.send(meth, *args, &block) } }.map{ |t| t.value }
  end

Create Elementor.

[Source]

# File lib/more/facets/elementor.rb, line 42
  def to_elem(meth=nil)
    Elementor.new(self, meth || :map)
  end

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

CREDIT: Trans

[Source]

# File lib/core/facets/to_hash.rb, line 265
  def to_h(mode=nil)
    to_a.to_h(mode)
  end

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

  (-5..5).to_a.uniq_by {|i| i*i }

produces

  [-5, -4, -3, -2, -1, 0]

[Source]

# File lib/core/facets/enumerable/uniq_by.rb, line 11
  def uniq_by #:yield:
    h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x}
  end

[Validate]