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.
[ + ]
# File lib/core/facets/enumerable/accumulate.rb, line 14 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
[ + ]
# 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
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
[ + ]
# 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
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
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
[ + ]
# 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 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 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
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
[ + ]
# 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
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
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
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
[ + ]
# 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
[ + ]
# 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 CREDIT: Louis J Scoras
[ + ]
# File lib/core/facets/enumerable/inject.rb, line 17 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
[ + ]
# File lib/core/facets/enumerable/map_send.rb, line 7 def map_send(meth, *args, &block) map{|e| e.send(meth, *args, &block)} end
Alias for collect_with_index
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 }
CREDIT: Trans CREDIT: Andrew Dudzik (adudzik)
NOTE: Would correlate would be better?
[ + ]
# File lib/core/facets/enumerable/mash.rb, line 15 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
[ + ]
# 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 this be better named ‘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
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
Returns a list on non-unique,
[1,1,2,2,3,4,5].nonuniq #=> [1,2] CREDIT: Martin DeMello
[ + ]
# 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] CREDIT: ?
[ + ]
# 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
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
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 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
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
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
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] CREDIT: ?
[ + ]
# File lib/core/facets/enumerable/uniq_by.rb, line 13 def uniq_by #:yield: h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x} end