Methods
accumulate cluster_by collect_with_index commonality compact_collect compact_map count divide duplicates each_by entropy frequency graph group_by ideal_entropy inject! map_send map_with_index mash mode modulate none? nonuniq occur one? probability split sum take to_h uniq_by
Public Instance methods
accumulate()

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

# 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
cluster_by(&b)

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

# 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() {|self[i], i| ...}

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

This method is also aliased as map_with_index
# File lib/core/facets/enumerable/collect.rb, line 10
  def collect_with_index
    r = []
    each_index do |i|
      r << yield(self[i], i)
    end
    r
  end
commonality( &block )

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

# 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

compact_map(trash=nil) {|*a| ...}

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

This method is also aliased as compact_collect
# File lib/core/facets/enumerable/collect.rb, line 37
  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(*c)

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

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

Divide on matching pattern.

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

CREDIT: Trans

# 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

each_by(steps=nil, &block)

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

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

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

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

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

CREDIT: Brian Schröder

# 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( {|| ...}

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

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

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

# 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
inject!(s) {|k, i| ...}

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

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

Send a message to each element and collect the result.

CREDIT: Sean O‘Halpin

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

Alias for collect_with_index

mash(&yld)

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

This method is also aliased as graph
# 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
mode()

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

CREDIT: Robert Klemme

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

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

# 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?( {|e| ...}

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

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

Returns a list on non-unique,

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

CREDIT: Martin DeMello

This method is also aliased as duplicates
# 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
occur(n=nil) {|| ...}

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]
# 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
one?( {|e| ...}

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

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

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

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

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

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

Uses #+ to sum the enumerated elements.

  [1,2,3].sum  #=> 6
  [3,3,3].sum  #=> 9
# 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)

Return the first n items from the collection

# 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
to_h(arrayed=nil)

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

CREDIT: Trans

# File lib/core/facets/to_hash.rb, line 65
  def to_h(arrayed=nil)
    to_a.to_h(arrayed)
  end
uniq_by( {|| ...}

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