Alias for product
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/core/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
This is more advnaced form of join. It allows for fine control of separators.
NOTE: The old version used to default it‘s separator to ", " and default the terminating separator to " and ". This is no longer the case. You must specifically provide these parameters.
[1,2,3].conjoin => "123" [1,2,3].conjoin(', ', ' and ') => "1, 2 and 3 [1,2,3].conjoin(', ', :last => ' or ') => "1, 2 or 3 [1,2,3].conjoin('; ', -1 => ' & ') => "1; 2 & 3 [1,2,3,4].conjoin{ |i, a, b| i % 2 == 0 ? '.' : '-' } => "1.2-3.4" [1,1,2,2].conjoin{ |i, a, b| a == b ? '=' : '!=' } => "1=1!=2=2"
CREDIT: Trans
[ + ]
# File lib/core/facets/array/conjoin.rb, line 30 def conjoin(*args, &block) return first.to_s if size < 2 sep = [] if block_given? (size - 1).times do |i| sep << yield(i, *slice(i,2)) end else options = (Hash===args.last) ? args.pop : {} separator = args.shift || "" options[-1] = args.shift unless args.empty? sep = [separator] * (size - 1) if options.key?(:last) options[-1] = options.delete(:last) end options[-1] ||= " and " options.each{|i, s| sep[i] = s} end zip(sep).join end
Inverse of delete_if.
[1,2,3].delete_unless{ |x| x < 2 } => [1,2]
CREDIT: Daniel Schierbeck
[ + ]
# File lib/core/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/core/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/core/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
Allows index to accept a block.
OVERRIDE! This is one of the bery few core overrides in Facets.
[ + ]
# File lib/core/facets/array/index.rb, line 12 def index(obj=nil, &block) if block_given? _facets_index(find(&block)) else _facets_index(obj) end end
In place merge.
a = [1,2] a.merge! [2,3] a => [1,2,3]
CREDIT: Trans
[ + ]
# File lib/core/facets/array/merge.rb, line 11 def merge!( other ) self.replace(self.merge(other)) end
Not empty?
[].not_empty? #=> false [1,2].not_empty? #=> true
[ + ]
# File lib/core/facets/array/not_empty.rb, line 8 def not_empty? !empty? end
Returns the only element in the array. Raises an IndexError if the array‘s size is not 1.
[5].only # -> 5 [1,2,3].only # -> IndexError [].only # -> IndexError
CREDIT: Gavin Sinclair, Noah Gibbs
[ + ]
# File lib/core/facets/array/only.rb, line 12 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 upto 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/core/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/core/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
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.
CREDIT: Shin-ichiro Hara
[ + ]
# File lib/core/facets/array/permutation.rb, line 11 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
Provides the cross-product of two or more Enumerables. This is the class-level method. The instance method calls on this.
Enumerable.cartesian_product([1,2], [4], ["apple", "banana"]) #=> [[1, 4, "apple"], [1, 4, "banana"], [2, 4, "apple"], [2, 4, "banana"]] Enumerable.cartesian_product([1,2], [3,4]) #=> [[1, 3], [1, 4], [2, 3], [2, 4]] a = [] [1,2].cart([4,5]){|elem| a << elem } a #=> [[1, 4],[1, 5],[2, 4],[2, 5]]
CREDIT: Thomas Hafner
[ + ]
# File lib/core/facets/array/product.rb, line 21 def product(*enums, &block) 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 if block_given? result.each{ |e| block.call(e) } else result end end
Apply a block to hash, and recursively apply that block to each subhash.
arr = ["a", ["b", "c", nil], nil] arr.recursively{|a| a.compact! } => ["a", ["b", "c"]]
TODO: Can this be generalized in Enumerbale?
[ + ]
# File lib/core/facets/array/recursively.rb, line 12 def recursively(&block) a = inject([]) do |array, value| if value.is_a?(Array) array << value.recursively(&block) else array << value end array end yield a end
In place form of recursively.
[ + ]
# File lib/core/facets/array/recursively.rb, line 26 def recursively!(&block) replace(recursively(&block)) end
Rotates an array‘s elements from back to front n times.
[1,2,3].rotate #=> [3,1,2] [3,1,2].rotate #=> [2,3,1] [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) #=> [2,3,1]
CREDIT: Florian Gross, Thomas Sawyer
[ + ]
# File lib/core/facets/array/rotate.rb, line 16 def rotate(n=1) self.dup.rotate!(n) end
Same as rotate, but acts in place.
a = [1,2,3] a.rotate! a #=> [3,1,2]
CREDIT: Florian Gross, Thomas Sawyer
[ + ]
# File lib/core/facets/array/rotate.rb, line 28 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/core/facets/array/select.rb, line 11 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 give 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/core/facets/array/splice.rb, line 17 def splice(*args) if args.size == 1 slice!(*args) else store(*args) end end
Boolean conversion for not empty?
[ + ]
# File lib/core/facets/boolean.rb, line 60 def to_b ! self.empty? end
Converts a two-element associative array into a hash.
a = [ [:a,1], [:b,2] ] a.to_h #=> { :a=>1, :b=>2 }
If arrayed is set it will maintain trailing arrays.
a = [ [:a,1,2], [:b,3] ] a.to_h(true) #=> { :a=>[1,2], :b=>[3] }
Note that the use of a values parameter has been deprecated because that functionality is as simple as:
array1.zip(array2).to_h
CREDIT: Trans
[ + ]
# File lib/core/facets/to_hash.rb, line 20 def to_h(arrayed=nil) h = {} if arrayed #or (flatten.size % 2 == 1) #each{ |e| h[e.first] = e.slice(1..-1) } each{ |k,*v| h[k] = v } else #h = Hash[*flatten(1)] # TODO Use in 1.9 instead. ary = [] each do |a| Array===a ? ary.concat(a) : ary << a end h = Hash[*ary] end h end
[ + ]
# File lib/core/facets/array/traverse.rb, line 5 def traverse(&block) map do |item| if item.is_a?(self.class) item.traverse(&block) else yield item end end end
[ + ]
# File lib/core/facets/array/traverse.rb, line 17 def traverse!(&block) replace(traverse(&block)) end