Array#** is an alias for Array#product.
NOTE: This method is not a common core extension and is not loaded automatically when using require 'facets'.
@uncommon
require 'facets/array/op_pow'
Returns the value after the given value. The value before the last is the first. Returns nil if the given value is not in the array.
Examples
sequence = ['a', 'b', 'c'] sequence.after('a') #=> 'b' sequence.after('b') #=> 'c' sequence.after('c') #=> 'a' sequence.after('d') #=> nil
CREDIT: Tyler Rick
# File lib/facets/array/before.rb, line 33 def after(value) return nil unless include? value self[(index(value).to_i + 1) % length] end
Returns the value previous to the given value. The value previous to the first is the last. Returns nil if the given value is not in the array.
Examples
sequence = ['a', 'b', 'c'] sequence.before('a') #=> 'c' sequence.before('b') #=> 'a' sequence.before('c') #=> 'b' sequence.before('d') #=> nil
CREDIT: Tyler Rick
# File lib/facets/array/before.rb, line 16 def before(value) return nil unless include? value self[(index(value).to_i - 1) % length] end
Simplify an array by flattening it then compacting it.
[1,[2,nil,[3]],nil,4].collapse #=> [1,2,3,4]
# File lib/facets/array/collapse.rb, line 7 def collapse flatten.compact end
Yields the block to each unique combination of n elements.
a = %w|a b c d| a.combination(3)
produces
[["a", "b", "c"], ["a", "b", "d"], ["a", "c", "d"], ["b", "c", "d"]]
CREDIT: Florian Gross
# File lib/facets/array/combination.rb, line 21 def combination(k=2) if block_given? s = to_a n = s.size return unless (1..n) === k idx = (0...k).to_a loop do yield s.values_at(*idx) i = k - 1 i -= 1 while idx[i] == n - k + i break if i < 0 idx[i] += 1 (i + 1 ... k).each {|j| idx[j] = idx[i] + j - i} end else to_enum(:combination, k) end 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, 2], 4 => [4, 4] } ["foo", "bar", "a"].commonality { |str| str.length } #=> { 3 => ["foo", "bar"] }
This can be useful, for instance, in determining all persons that share their last name with another person ...
persons.collisions { |person| person.last_name }
CREDIT: Florian Gross
# File lib/facets/array/commonality.rb, line 19 def commonality(&block) had_no_block = !block block ||= lambda { |item| item } result = Hash.new { |hash, key| hash[key] = Array.new } 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
This is more advanced form of join. It allows for fine control of separators.
NOTE: The old version used to default its separator to ", " and default the terminating separator to " and ". This is no longer the case. You must specifically provide these parameters.
If no paramters are given, it acts like join but will a space separator.
[1,2,3].conjoin #=> "1 2 3"
Use comma+space and 'and' on tail.
[1,2,3].conjoin(', ', ' and ') #=> "1, 2 and 3"
Use comma+space and 'or' on tail using :last option.
[1,2,3].conjoin(', ', :last => ' or ') #=> "1, 2 or 3"
Use semicolon+space and ampersand on tail using index.
[1,2,3].conjoin('; ', -1 => ' & ') #=> "1; 2 & 3"
Can take a block to determine separator.
[1,2,3,4].conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' } #=> "1.2-3.4"
This makes very esoteric transformation possible.
[1,1,2,2].conjoin{ |i, a, b| a == b ? '=' : ' != ' } #=> "1=1 != 2=2" [1,2,3,4].conjoin{ |i, x, y| "<#{i} #{x} #{y}>" } #=> "1<0 1 2>2<1 2 3>3<2 3 4>4"
There are also spacing options. Providing the :space option pads the separators.
[1,2,3].conjoin(',', '&', :space=>2) #=> "1 , 2 & 3"
And the :spacer option can set an alternate spacing string.
[1,2,3].conjoin('|', '>', :space=>2, :spacer=>'-') #=> "1--|--2-->--3"
CREDIT: Trans
# File lib/facets/array/conjoin.rb, line 57 def conjoin(*args, &block) return first.to_s if size < 2 options = (Hash===args.last) ? args.pop : {} spacing = options.delete(:space) || 0 spacer = options.delete(:spacer) || " " space = spacer * spacing.to_i sep = [] if block_given? (size - 1).times do |i| sep << space + yield(i, *slice(i,2)) + space end else separator = args.shift || " " options[-1] = args.shift if args.first options[0] = options.delete(:first) if options.key?(:first) options[-1] = options.delete(:last) if options.key?(:last) separator = space + separator + space sep = [separator] * (size - 1) options.each{|i, s| sep[i] = space + s + space} end zip(sep).join end
Inverse of delete_if.
[1,2,3].delete_unless{ |x| x < 2 } #=> [1]
CREDIT: Daniel Schierbeck
# File lib/facets/array/delete_unless.rb, line 10 def delete_unless(&block) delete_if { |element| not block.call(element) } end
Delete multiple values from array.
a = [1,2,3,4] a.delete_values(1,2) #=> [1,2] a #=> [3,4]
CREDIT: Trans
# File lib/facets/array/delete_values.rb, line 11 def delete_values(*values) d = [] values.each{ |v| d << delete(v) } d end
Delete multiple values from array given indexes or index range.
a = [1,2,3,4] a.delete_values_at(1,2) #=> [2,3] a #=> [1,4] a = [1,2,3,4] a.delete_values_at(0..2) #=> [1,2,3] a #=> [4]
NOTE: It would be nice to see delete_at incorporate this funcitonaility.
CREDIT: Trans
# File lib/facets/array/delete_values.rb, line 32 def delete_values_at(*selectors) idx = [] selectors.each{ |i| case i when Range idx.concat( i.to_a ) else idx << i.to_i end } idx.uniq! dvals = values_at(*idx) idx = (0...size).to_a - idx self.replace( values_at(*idx) ) return dvals end
Divide on matching pattern.
['a1','b1','a2','b2'].divide(/^a/) #=> [['a1','b1'],['a2','b2']]
CREDIT: Trans
# File lib/facets/array/divide.rb, line 10 def divide(pattern) memo = [] each do |obj| memo.push [] if pattern === obj memo.last << obj end memo end
Iterate over index and value. The intention of this method is to provide polymorphism with Hash.
# File lib/facets/array/each_pair.rb, line 6 def each_pair #:yield: i = -1 each_value do |x| yield(i+=1, x) 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.
e = %w{ a b c d e e e }.entropy ("%.3f" % e) #=> "2.128"
CREDIT: Derek
# File lib/facets/array/entropy.rb, line 16 def entropy arr = self 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
Extracts options from a set of arguments. Removes and returns the last element in the array if it's a hash, otherwise returns a blank hash.
def options(*args) args.extract_options! end options(1, 2) # => {} options(1, 2, :a => :b) # => {:a=>:b}
# File lib/facets/array/extract_options.rb, line 23 def extract_options! if Hash === last && last.extractable_options? pop else {} end end
Returns last n elements.
%w{W o r l d}.from(3) #=> %w{l d}
# File lib/facets/array/from.rb, line 7 def from(i) return self if i >= size self[i, size - i] 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/facets/array/entropy.rb, line 32 def ideal_entropy arr = self 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
Determines the sorted middle element.
a = %w{a a b b c c c} a.median #=> "b"
When there are an even number of elements, the greater of the two middle elements is given.
a = %w{a a b b c c c d} a.median #=> "c"
An offset can be supplied to get an element relative to the middle.
a = %w{a a b b c c c d} a.median(-1) #=> "b"
The the array is empty, nil is returned.
@return [Object] sorted middle element
# File lib/facets/array/median.rb, line 23 def median(offset=0) return nil if self.size == 0 tmp = self.sort mid = (tmp.size / 2).to_i + offset tmp[mid] end
In place merge.
a = [1,2] a.merge! [2,3] a #=> [1,2,3]
CREDIT: Trans
# File lib/facets/array/merge.rb, line 11 def merge!( other ) self.replace(self.merge(other)) end
In Statistics mode is the value that occurs most frequently in a given set of data. This method returns an array in case their is a tie.
[:a, :b, :c, :b, :d].mode #=> [:b] [:a, :b, :c, :b, :a].mode #=> [:a, :b]
Returns an Array of most common elements.
@author Robert Klemme
# File lib/facets/array/mode.rb, line 14 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
Not empty?
[].not_empty? #=> false [1,2].not_empty? #=> true
# File lib/facets/array/not_empty.rb, line 8 def not_empty? !empty? end
# File lib/facets/object/object_state.rb, line 47 def object_state(data=nil) data ? replace(data) : dup end
Returns the only element in the array. Raises an IndexError if the array's size is not 1.
[5].only # => 5 expect IndexError do [1,2,3].only end expect IndexError do [].only end
CREDIT: Gavin Sinclair, Noah Gibbs
# File lib/facets/array/only.rb, line 18 def only unless size == 1 raise IndexError, "Array#only called on non-single-element array" end first end
Pad an array with a given value up to a given length.
[0,1,2].pad(6,"a") #=> [0,1,2,"a","a","a"]
If length is a negative number padding will be added to the beginning of the array.
[0,1,2].pad(-6,"a") #=> ["a","a","a",0,1,2]
CREDIT: Richard Laugesen
# File lib/facets/array/pad.rb, line 14 def pad(len, val=nil) return dup if self.size >= len.abs if len < 0 Array.new((len+size).abs,val) + self else self + Array.new(len-size,val) end end
Like pad but changes the array in place.
a = [0,1,2] a.pad!(6,"x") a #=> [0,1,2,"x","x","x"]
CREDIT: Richard Laugesen
# File lib/facets/array/pad.rb, line 31 def pad!(len, val=nil) return self if self.size >= len.abs if len < 0 replace Array.new((len+size).abs,val) + self else concat Array.new(len-size,val) end end
Peek at the top of the stack (the end of the array).
a = [1, 2, 3] a.peek #=> 3 a #=> [1, 2, 3]
Or provide an index to inspect the array from back to front.
# File lib/facets/array/pull.rb, line 14 def peek(i=0) i = -(i + 1) fetch(i) end
Permutation provids the possible orders of an enumerable. Each is indexed by a permutation number. The maximum number of arrangements is the factorial of the size of the array.
[1,2].permutation(2).to_a #=> [[1,2], [2,1]]
CREDIT: Shin-ichiro Hara
# File lib/facets/array/permutation.rb, line 13 def permutation(n=size) if size < n or n < 0 elsif n == 0 yield([]) else self[1..-1].permutation(n - 1) do |x| (0...n).each do |i| yield(x[0...i] + [first] + x[i..-1]) end end self[1..-1].permutation(n) do |x| yield(x) end end end
Put an object on the bottom of the stack (front of the array).
a = [2, 3] a.poke(1) a #=> [1, 2, 3]
Or supply an index and poke works like insert.
# File lib/facets/array/pull.rb, line 26 def poke(x, i=0) insert(i,x) end
Provides the cartesian product of two or more arrays.
a = [1,2].product([4,5]) a #=> [[1, 4],[1, 5],[2, 4],[2, 5]]
CREDIT: Thomas Hafner
# File lib/facets/array/product.rb, line 12 def product(*enums) enums.unshift self result = [[]] while [] != enums t, result = result, [] b, *enums = enums t.each do |a| b.each do |n| result << a + [n] end end end result end
Apply a block to array, and recursively apply that block to each sub-array or types.
arr = ["a", ["b", "c", nil], nil] arr.recurse{ |a| a.compact! } #=> ["a", ["b", "c"]]
# File lib/facets/array/recurse.rb, line 10 def recurse(*types, &block) types = [self.class] if types.empty? a = inject([]) do |array, value| case value when *types array << value.recurse(*types, &block) else array << value end array end yield a end
In place form of recurse.
# File lib/facets/array/recurse.rb, line 25 def recurse!(&block) replace(recurse(&block)) end
Apply a method to array, and recursively apply that method to each sub-array or types.
arr = ["a", ["b", "c"]] arr.recursively.map{ |v| v.to_sym } #=> [:a, [:b, :c]]
By default the sub-types are passed thru uneffected. Passing a block to recursively changes this.
arr = ["a", ["b", "c"]] arr.recursively{ |a| a.reverse }.map{ |v| v.to_sym } #=> [:a, [:c, :b]]
TODO: Return Enumerator if no yld block is given ?
# File lib/facets/array/recursively.rb, line 21 def recursively(*types, &block) Recursor.new(self, *types, &block) end
Rotates an array's elements from back to front n times.
[1,2,3].rotate #=> [2,3,1] [2,3,1].rotate #=> [3,1,2] [3,1,2].rotate #=> [1,2,3] [1,2,3].rotate(3) #=> [1,2,3]
A negative parameter reverses the order from front to back.
[1,2,3].rotate(-1) #=> [3,1,2]
CREDIT: Florian Gross, Thomas Sawyer
# File lib/facets/array/rotate.rb, line 19 def rotate(n=1) self.dup.rotate!(n) end
Same as rotate, but acts in place.
a = [1,2,3] a.rotate! a #=> [2,3,1]
CREDIT: Florian Gross, Thomas Sawyer
# File lib/facets/array/rotate.rb, line 35 def rotate!(n=1) n = n.to_int return self if (n == 0 or self.empty?) if n < 0 n.abs.times{ self.unshift( self.pop ) } else n.abs.times{ self.push( self.shift ) } end self end
As with select but modifies the Array in place.
a = [1,2,3,4,5,6,7,8,9,10] a.select!{ |e| e % 2 == 0 } a #=> [2,4,6,8,10]
CREDIT: Gavin Sinclair
# File lib/facets/array/select.rb, line 13 def select! # :yield: reject!{ |e| not yield(e) } end
Splice acts a combination of slice! and store. If two arguments are given it calls store. If a single argument is given it calls slice!.
a = [1,2,3] a.splice(1) #=> 2 a #=> [1,3] a = [1,2,3] a.splice(1,4) #=> 4 a #=>[1,4,3]
CREDIT: Trans
# File lib/facets/array/splice.rb, line 19 def splice(*args) if args.size == 1 slice!(*args) else store(*args) end 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/facets/array/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
Fetch values from a start index thru an end index.
[1,2,3,4,5].thru(0,2) #=> [1,2,3] [1,2,3,4,5].thru(2,4) #=> [3,4,5] [1,2,3,4,5].thru(2) #=> [1,2,3] [1,2,3,4,5].thru(4) #=> [1,2,3,4,5]
# File lib/facets/array/from.rb, line 20 def thru(from, to=nil) from, to = 0, from unless to to = size - 1 if to >= size a = [] i = from while i <= to a << self[i] i += 1 end a end
Boolean conversion for not empty?
# File lib/facets/boolean.rb, line 110 def to_b ! self.empty? end
Returns a new array created by traversing the array and its sub-arrays, executing the given block on the elements.
h = ["A", "B", ["X", "Y"]] g = h.traverse{ |e| e.downcase } g #=> ["a", "b", ["x", "y"]]
This is the same as recursive.map and will likely be deprecated in the future because of it.
CREDIT: Trans
# File lib/facets/array/traverse.rb, line 16 def traverse(&block) if block_given? map do |e| if e.respond_to?(:to_ary) e.to_ary.traverse(&block) else block.call(e) end end else to_enum(:traverse) end end
Like recursive_map, but will change the array in place.
h = ["A", "B", ["X", "Y"]] h.traverse!{ |e| e.downcase } h #=> ["a", "b", ["x", "y"]]
CREDIT: Trans
# File lib/facets/array/traverse.rb, line 39 def traverse!(&block) replace(traverse(&block)) end
Like uniq, but determines uniqueness based on a given block.
a = (-5..5).to_a a.uniq_by!{ |i| i*i } a #=> [-5, -4, -3, -2, -1, 0]
As can be seen in the example, order is significant.
# File lib/facets/array/uniq_by.rb, line 10 def uniq_by! #:yield: h = {} replace( inject([]){|a,x| h[yield(x)] ||= a << x} ) end
Generated with the Darkfish Rdoc Generator 2.