Class: Array

Inherits:
Object show all
Includes:
Indexable, Random::ArrayExtensions
Defined in:
lib/core/facets/boolean.rb,
lib/core/facets/to_hash.rb,
lib/standard/facets/set.rb,
lib/core/facets/array/pad.rb,
lib/core/facets/array/from.rb,
lib/core/facets/array/mode.rb,
lib/core/facets/array/only.rb,
lib/core/facets/array/pull.rb,
lib/standard/facets/random.rb,
lib/core/facets/array/index.rb,
lib/core/facets/array/merge.rb,
lib/core/facets/array/split.rb,
lib/core/facets/array/store.rb,
lib/core/facets/array/before.rb,
lib/core/facets/array/divide.rb,
lib/core/facets/array/rotate.rb,
lib/core/facets/array/select.rb,
lib/core/facets/array/splice.rb,
lib/core/facets/kernel/blank.rb,
lib/core/facets/array/conjoin.rb,
lib/core/facets/array/entropy.rb,
lib/core/facets/array/nonuniq.rb,
lib/core/facets/array/product.rb,
lib/core/facets/array/recurse.rb,
lib/core/facets/array/uniq_by.rb,
lib/supplemental/facets/tuple.rb,
lib/core/facets/array/collapse.rb,
lib/core/facets/array/contains.rb,
lib/core/facets/array/traverse.rb,
lib/standard/facets/shellwords.rb,
lib/core/facets/array/indexable.rb,
lib/core/facets/array/not_empty.rb,
lib/core/facets/enumerable/count.rb,
lib/core/facets/array/combination.rb,
lib/core/facets/array/commonality.rb,
lib/core/facets/array/permutation.rb,
lib/core/facets/array/probability.rb,
lib/core/facets/array/recursively.rb,
lib/core/facets/array/delete_unless.rb,
lib/core/facets/array/delete_values.rb,
lib/core/facets/object/object_state.rb,
lib/core-uncommon/facets/array/median.rb,
lib/core-uncommon/facets/array/op_pow.rb,
lib/core/facets/array/extract_options.rb,
lib/core-uncommon/facets/array/percentile.rb

Instance Method Summary collapse

Methods included from Indexable

#body, #ends, #first, #first=, #foot, #head, #last, #last=, #mid, #middle, #pos, #range, #tail

Methods included from Random::ArrayExtensions

#at_rand, #at_rand!, #pick, #pick!, #rand_index, #rand_subset, #shuffle, #shuffle!

Instance Method Details

#_facets_indexObject



5
# File 'lib/core/facets/array/index.rb', line 5

alias_method :_facets_index, :index

#after(value) ⇒ Object

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



33
34
35
36
# File 'lib/core/facets/array/before.rb', line 33

def after(value)
  return nil unless include? value
  self[(index(value).to_i + 1) % length]
end

#before(value) ⇒ Object

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



16
17
18
19
# File 'lib/core/facets/array/before.rb', line 16

def before(value)
  return nil unless include? value
  self[(index(value).to_i - 1) % length]
end

#collapseObject

Simplify an array by flattening it then compacting it.

[1,[2,nil,[3]],nil,4].collapse  #=> [1,2,3,4]


7
8
9
# File 'lib/core/facets/array/collapse.rb', line 7

def collapse
  flatten.compact
end

#combination(k = 2) ⇒ Object

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



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 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

#commonality(&block) ⇒ Object Also known as: collisions

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



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/core/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

#conjoin(*args, &block) ⇒ Object

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



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/core/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

#delete_unless(&block) ⇒ Object

Inverse of #delete_if.

[1,2,3].delete_unless{ |x| x < 2 }
#=> [1]

CREDIT: Daniel Schierbeck



10
11
12
# File 'lib/core/facets/array/delete_unless.rb', line 10

def delete_unless(&block)
  delete_if { |element| not block.call(element) }
end

#delete_values(*values) ⇒ Object

Delete multiple values from array.

a = [1,2,3,4]
a.delete_values(1,2)   #=> [1,2]
a                      #=> [3,4]

CREDIT: Trans



11
12
13
14
15
# File 'lib/core/facets/array/delete_values.rb', line 11

def delete_values(*values)
  d = []
  values.each{ |v| d << delete(v) }
  d
end

#delete_values_at(*selectors) ⇒ Object

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



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 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

#divide(pattern) ⇒ Object

Divide on matching pattern.

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

CREDIT: Trans



10
11
12
13
14
15
16
17
# File 'lib/core/facets/array/divide.rb', line 10

def divide(pattern)
  memo = []
  each do |obj|
    memo.push [] if pattern === obj
    memo.last << obj
  end
  memo
end

#entropyObject

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



16
17
18
19
20
21
22
23
24
# File 'lib/core/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

#extract_options!Object

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}


23
24
25
26
27
28
29
# File 'lib/core/facets/array/extract_options.rb', line 23

def extract_options!
  if Hash === last && last.extractable_options?
    pop
  else
    {}
  end
end

#from(i) ⇒ Object

Returns last n elements.

%w{W o r l d}.from(3)  #=> %w{l d}


7
8
9
10
# File 'lib/core/facets/array/from.rb', line 7

def from(i)
  return self if i >= size
  self[i, size - i]
end

#ideal_entropyObject

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



32
33
34
35
36
# File 'lib/core/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

#index(obj = nil, &block) ⇒ Object

Allows #index to accept a block.

['a', 'b', 'c'].index{ |x| x.upcase == 'C' } #=> 2

IMPORTANT: This is one of the few core overrides in Facets.



12
13
14
15
16
17
18
# 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

#medianObject

Returns the median for the array; nil if array is empty.

NOTE: This is not (presently) a common core extension and is not loaded automatically when using require 'facets'. – TODO: Does Array#median belong in a math-oriented library? ++



12
13
14
# File 'lib/core-uncommon/facets/array/median.rb', line 12

def median
  percentile(50)
end

#merge!(other) ⇒ Object

In place #merge.

a = [1,2]
a.merge! [2,3]
a #=> [1,2,3]

CREDIT: Trans



11
12
13
# File 'lib/core/facets/array/merge.rb', line 11

def merge!( other )
  self.replace(self.merge(other))
end

#modeObject

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.

CREDIT: Robert Klemme



14
15
16
17
18
19
# File 'lib/core/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

#nonuniqObject Also known as: duplicates

Returns a list of non-unique elements

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

CREDIT: Martin DeMello



9
10
11
12
13
14
15
16
17
# File 'lib/core/facets/array/nonuniq.rb', line 9

def nonuniq
  h1 = {}
  h2 = {}
  each {|i|
    h2[i] = true if h1[i]
    h1[i] = true
  }
  h2.keys
end

#nonuniq!Object



20
21
22
23
24
25
26
27
28
# File 'lib/core/facets/array/nonuniq.rb', line 20

def nonuniq!
  h1 = {}
  h2 = {}
  each {|i|
    h2[i] = true if h1[i]
    h1[i] = true
  }
  self.replace(h2.keys)
end

#not_empty?Boolean

Not empty?

[].not_empty?     #=> false
[1,2].not_empty?  #=> true

Returns:

  • (Boolean)


8
9
10
# File 'lib/core/facets/array/not_empty.rb', line 8

def not_empty?
  !empty?
end

#object_state(data = nil) ⇒ Object



47
48
49
# File 'lib/core/facets/object/object_state.rb', line 47

def object_state(data=nil)
  data ? replace(data) : dup
end

#onlyObject

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



18
19
20
21
22
23
# File 'lib/core/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(len, val = nil) ⇒ Object

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



14
15
16
17
18
19
20
21
# 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

#pad!(len, val = nil) ⇒ Object

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



31
32
33
34
35
36
37
38
# 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

#peek(i = 0) ⇒ Object

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.



14
15
16
17
# File 'lib/core/facets/array/pull.rb', line 14

def peek(i=0)
  i = -(i + 1)
  fetch(i)
end

#percentile(p) ⇒ Object

Returns the percentile value for percentile p; nil if array is empty.

p should be expressed as an integer; percentile(90) returns the 90th percentile of the array.

Algorithm from NIST

NOTE: This is not (presently) a common core extension and is not loaded automatically when using require 'facets'.

CREDT: ?



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/core-uncommon/facets/array/percentile.rb', line 15

def percentile(p)
  sorted_array = self.sort
  rank = (p.to_f / 100) * (self.length + 1)

  if self.length == 0
    return nil
  elsif rank.to_i == rank #fractional_part?
    sample_0 = sorted_array[rank.truncate - 1]
    sample_1 = sorted_array[rank.truncate]

    fractional_part = rank.abs.modulo(1)
    return (fractional_part * (sample_1 - sample_0)) + sample_0
  else
    return sorted_array[rank.to_i - 1]
  end    
end

#permutation(n = size) ⇒ Object

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



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/core/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

#poke(x, i = 0) ⇒ Object

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.



26
27
28
# File 'lib/core/facets/array/pull.rb', line 26

def poke(x, i=0)
  insert(i,x)
end

#power_setObject



20
21
22
23
24
25
26
27
28
29
# File 'lib/standard/facets/set.rb', line 20

def power_set
  if empty?
    [self]
  else
    subset  = dup
    value   = [ subset.pop ]
    subsubs = subset.power_set
    subsubs.concat( subsubs.map{ |subset| subset + value } )
  end
end

#probabilityObject

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

[:a, :b, :c, :c].probability  #=> {:a=> 0.25, :b=>0.25, :c=>0.5}

CREDIT: Brian Schröder



10
11
12
13
14
15
16
17
18
19
# File 'lib/core/facets/array/probability.rb', line 10

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

#product(*enums) ⇒ Object Also known as: **

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



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/core/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

#recurse(*types) {|a| ... } ⇒ Object

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

Yields:

  • (a)


10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/core/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

#recurse!(&block) ⇒ Object

In place form of #recurse.



25
26
27
# File 'lib/core/facets/array/recurse.rb', line 25

def recurse!(&block)
  replace(recurse(&block))
end

#recursively(*types, &block) ⇒ Object

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 ?



21
22
23
# File 'lib/core/facets/array/recursively.rb', line 21

def recursively(*types, &block)
  Recursor.new(self, *types, &block)
end

#rotate(n = 1) ⇒ Object

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



19
20
21
# File 'lib/core/facets/array/rotate.rb', line 19

def rotate(n=1)
  self.dup.rotate!(n)
end

#rotate!(n = 1) ⇒ Object

Same as #rotate, but acts in place.

a = [1,2,3]
a.rotate!
a  #=> [2,3,1]

CREDIT: Florian Gross, Thomas Sawyer



35
36
37
38
39
40
41
42
43
44
# File 'lib/core/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

#select!Object

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



13
14
15
# File 'lib/core/facets/array/select.rb', line 13

def select!  # :yield:
  reject!{ |e| not yield(e) }
end

#shelljoinObject



78
79
80
# File 'lib/standard/facets/shellwords.rb', line 78

def shelljoin
  Shellwords.shelljoin(shellwords)
end

#shellwordsObject

Convert an array into command line parameters. The array is accepted in the format of Ruby method arguments –ie. [arg1, arg2, …, hash]



71
72
73
74
75
# File 'lib/standard/facets/shellwords.rb', line 71

def shellwords
  opts, args = *flatten.partition{ |e| Hash === e }
  opts = opts.inject({}){ |m,h| m.update(h); m }
  opts.shellwords + args
end

#splice(*args) ⇒ Object

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



19
20
21
22
23
24
25
# File 'lib/core/facets/array/splice.rb', line 19

def splice(*args)
  if args.size == 1
    slice!(*args)
  else
    store(*args)
  end
end

#split(pattern) ⇒ Object

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



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/core/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

#thru(from, to = nil) ⇒ Object

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]


20
21
22
23
24
25
26
27
28
29
30
# File 'lib/core/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

#to_bObject

Boolean conversion for not empty?



110
111
112
# File 'lib/core/facets/boolean.rb', line 110

def to_b
  ! self.empty?
end

#to_h(mode = nil) ⇒ Object

Converts an array into a hash. Converting an array into a hash is not a one-to-one conversion, for this reason #to_h examines at the array being converted and then dispatches the conversion to the most sutiable specialized function. There are three possiblities for this.

If the array is a collection of perfect pairs, like that which Hash#to_a generates, then conversion is handled by #to_h_flat.

a = [ [:a,1], [:b,2] ]
a.to_h  #=> { :a=>1, :b=>2 }

If the array contains only arrays, but are not perfect pairs, then #to_h_multi is called.

a = [ [:a,1,2], [:b,2], [:c], [:d] ]
a.to_h  #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] }

If the array contians objects other then arrays then the #to_h_splat method is called.

a = [ [:a,1,2], 2, :b, [:c,3], 9 ]
a.to_h  #=> { [:a,1,2]=>2, :b=>[:c,3], 9=>nil }

Finally, a particular dispatch can be forced by specifying the mode of conversion, eg. :multi, :splat, :flat, :assoc, etc.

Setting mode to true is the same as setting it :multi. This has been left in for backward compatability.

NOTE: The use of a values parameter has been deprecated because that functionality is as simple as …

array1.zip(array2).to_h

CREDIT: Robert Klemme, Trans

– The True option in the case statement provides some backward compatability with the previous versions of this method. ++



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/core/facets/to_hash.rb', line 51

def to_h(mode=nil)
  case mode
  when :splat
    return to_h_splat
  when :flat
    return to_h_flat
  when :multi, true
    return to_h_multi
  when :assoc
    return to_h_assoc
  else
    return to_h_auto
  end
end

#to_h_assocObject

When a mixed or multi-element accociative array is used, the result is as follows:

a = [ [:a,1,2], [:b,2], [:c], :d ]
a.to_h  #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] }

If the first entry of any subelements are the same, then the value will be set to the last occuring value.

a = [ :x, [:x], [:x,1,2], [:x,3], [:x,4] ]
a.to_h_assoc  #=> { :x=>[4] }


157
158
159
160
161
162
163
# File 'lib/core/facets/to_hash.rb', line 157

def to_h_assoc
  h = {}
  each do |k,*v| 
    h[k] = v
  end
  h
end

#to_h_autoObject

Converts an array into a hash. Converting an array into a hash is not a one-to-one conversion, for this reason #to_h examines at the array being converted and then dispatches the conversion to the most sutiable specialized function. There are three possiblities for this.

If the array is a collection of perfect pairs, like that which Hash#to_a generates, then conversion is handled by #to_h_flat.

a = [ [:a,1], [:b,2] ]
a.to_h_auto  #=> { :a=>1, :b=>2 }

If the array contains only arrays, but are not perfect pairs, then #to_h_multi is called.

a = [ [:a,1,2], [:b,2], [:c], [:d] ]
a.to_h_auto  #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] }

If the array contians objects other then arrays then the #to_h_splat method is called.

a = [ [:a,1,2], 2, :b, [:c,3], 9 ]
a.to_h_auto  #=> { [:a,1,2]=>2, :b=>[:c,3], 9=>nil }


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/core/facets/to_hash.rb', line 91

def to_h_auto
  pairs = true
  mixed = false

  each do |e|
    case e
    when Array
      pairs = false if e.size > 2
    else
      mixed = true
    end
  end

  if mixed
    to_h_splat
  elsif pairs
    to_h_flat
  else
    to_h_multi
  end
end

#to_h_flatObject

This is equivalent to Hash, but it will pad the array with a nil object if there are not an even number of elements.

a = [:a,1,[:b,2,:c]]
a.to_h_flat  #=> { :a=>1, :b=>2, :c=>nil }


133
134
135
136
137
# File 'lib/core/facets/to_hash.rb', line 133

def to_h_flat
  a = flatten
  a << nil if a.size % 2 == 1
  Hash[*a]
end

#to_h_multiObject

When a mixed or multi-element accociative array is used, the result is as follows:

a = [ [:a,1,2], [:b,2], [:c], :d ]
a.to_h  #=> { :a=>[1,2], :b=>[2], :c=>[], :d=>[] }

If the first entry of the subelements is the same, then the values will be merged using #concat.

a = [ [:a,1,2], [:a,3], [:a,4], [:a], :a ]
a.to_h_multi  #=> { :a=>[1,2,3,4] }


177
178
179
180
181
182
183
184
# File 'lib/core/facets/to_hash.rb', line 177

def to_h_multi
  h = {}
  each do |k,*v| 
    h[k] ||= []
    h[k].concat(v)
  end
  h
end

#to_h_splatObject

This is equivalent to Hash, but it will pad the array with a nil object if there are not an even number of elements.

a = [:a,1,:b,2,:c]
a.to_h_splat  #=> { :a=>1, :b=>2, :c=>nil }


120
121
122
123
124
# File 'lib/core/facets/to_hash.rb', line 120

def to_h_splat
  a = dup
  a << nil if a.size % 2 == 1
  Hash[*a]
end

#to_tObject

Convert an array into a tuple.



276
277
278
# File 'lib/supplemental/facets/tuple.rb', line 276

def to_t
  Tuple.cast_from_array( self )
end

#traverse(&block) ⇒ Object

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



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/core/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

#traverse!(&block) ⇒ Object

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



39
40
41
# File 'lib/core/facets/array/traverse.rb', line 39

def traverse!(&block)
  replace(traverse(&block))
end

#uniq_by!Object

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.



10
11
12
13
# File 'lib/core/facets/array/uniq_by.rb', line 10

def uniq_by! #:yield:
  h = {}
  replace( inject([]){|a,x| h[yield(x)] ||= a << x} )
end