Module: Enumerable

Defined in:
lib/abstractivator/enumerable_ext.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_default(default, other_side_value) ⇒ Object



43
44
45
# File 'lib/abstractivator/enumerable_ext.rb', line 43

def self.get_default(default, other_side_value)
  default.callable? ? default.call(other_side_value) : default
end

.inner_join(left, right, get_left_key, get_right_key) ⇒ Object



37
38
39
40
41
# File 'lib/abstractivator/enumerable_ext.rb', line 37

def self.inner_join(left, right, get_left_key, get_right_key)
  sentinel = Object.new
  result = self.outer_join(left, right, get_left_key, get_right_key, sentinel, sentinel)
  result.reject { |pair| pair.first == sentinel || pair.last == sentinel }
end

.outer_join(left, right, get_left_key, get_right_key, left_default, right_default) ⇒ Object

joins items from left with items from right based on their keys. get_left,right_key are callables which, given an item, return the item’s key. the defaults are used to form a pair for items which have no match. returns an array of 2-element arrays, each of which is a left/right pair.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/abstractivator/enumerable_ext.rb', line 10

def self.outer_join(left, right, get_left_key, get_right_key, left_default, right_default)

  ls = left.inject({}) { |h, x| h.store(get_left_key.call(x), x); h }   # Avoid #hash_map and Array#to_h
  rs = right.inject({}) { |h, x| h.store(get_right_key.call(x), x); h } #   for better performance

  raise 'duplicate left keys' if ls.size < left.size
  raise 'duplicate right keys' if rs.size < right.size

  result = []

  ls.each_pair do |k, l|
    r = rs[k]
    if r
      rs.delete(k)
    else
      r = get_default(right_default, l)
    end
    result.push [l, r]
  end

  rs.each_pair do |_, r|
    result.push [get_default(left_default, r), r]
  end

  result
end

.proc?(x) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
# File 'lib/abstractivator/enumerable_ext.rb', line 47

def self.proc?(x)
  x.respond_to?(:call)
end

Instance Method Details

#cyclic_fold(init, get_children_proc) {|acc, node| ... } ⇒ Object

Folds over a cyclic graph. ‘self’ is the root node set. Each node is visited once, in an unspecified order. Node identity is determined by #object_id

Parameters:

  • init (Object)

    the initial accumulator

  • get_children_proc (Proc)

    takes a node and returns its children (or neighbors)

Yield Parameters:

  • acc (Object)

    the accumulator

  • node (Object)

    the current node

Yield Returns:

  • (Object)

    the accumulator, after visiting all nodes once



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/abstractivator/enumerable_ext.rb', line 135

def cyclic_fold(init, get_children_proc, &block)
  xs = self.dup
  seen = Set.new
  acc = init
  while xs.any?
    x = xs.shift
    if seen.include?(x.object_id)
      next
    else
      seen.add(x.object_id)
      acc = block.call(acc, x)
      xs.concat(get_children_proc.call(x))
    end
  end
  acc
end

#duplicates(&block) ⇒ Object



121
122
123
124
125
# File 'lib/abstractivator/enumerable_ext.rb', line 121

def duplicates(&block)
  group_by(&block)
    .select { |_, vs| vs.size > 1 }
    .map { |k, _| k }
end

#fold_right(*args, &combine) ⇒ Object



152
153
154
# File 'lib/abstractivator/enumerable_ext.rb', line 152

def fold_right(*args, &combine)
  reverse.reduce(*args, &combine&.reverse_args)
end

#hash_map(get_key = ->x{x}, &get_value) ⇒ Object



51
52
53
# File 'lib/abstractivator/enumerable_ext.rb', line 51

def hash_map(get_key=->x{x}, &get_value)
  Hash[self.map{|x| [Proc.loose_call(get_key, [x]), get_value ? get_value.call(x) : x]}]
end

#inject_right(*args, &block) ⇒ Object



87
88
89
# File 'lib/abstractivator/enumerable_ext.rb', line 87

def inject_right(*args, &block)
  self.reverse_each.inject(*args, &block) # reverse_each to avoid duplicating the enumerable, when possible
end

#inner_join(right, get_left_key, get_right_key) ⇒ Object



59
60
61
# File 'lib/abstractivator/enumerable_ext.rb', line 59

def inner_join(right, get_left_key, get_right_key)
  Enumerable.inner_join(self, right, get_left_key, get_right_key)
end

#outer_join(right, get_left_key, get_right_key, default_value) ⇒ Object



55
56
57
# File 'lib/abstractivator/enumerable_ext.rb', line 55

def outer_join(right, get_left_key, get_right_key, default_value)
  Enumerable.outer_join(self, right, get_left_key, get_right_key, default_value, default_value)
end

#pad_right(n, value = nil, &block) ⇒ Object



91
92
93
94
# File 'lib/abstractivator/enumerable_ext.rb', line 91

def pad_right(n, value=nil, &block)
  block ||= proc { value }
  self + ([n-self.size, 0].max).times.map(&block)
end

#select_map(&block) ⇒ Object



106
107
108
# File 'lib/abstractivator/enumerable_ext.rb', line 106

def select_map(&block)
  self.map(&block).select { |x| x }
end

#singleObject



110
111
112
113
114
115
# File 'lib/abstractivator/enumerable_ext.rb', line 110

def single
  if size != 1
    raise ArgumentError, "expected a single element but was: #{inspect}"
  end
  self.first
end

#stable_sort(&compare) ⇒ Object



96
97
98
99
100
101
102
103
104
# File 'lib/abstractivator/enumerable_ext.rb', line 96

def stable_sort(&compare)
  compare = compare || ->(a, b){a <=> b}
  xis = self.each_with_index.map{|x, i| [x, i]}
  sorted = xis.sort do |(a, ai), (b, bi)|
    primary = compare.call(a, b)
    primary != 0 ? primary : (ai <=> bi)
  end
  sorted.map(&:first)
end

#uniq?Boolean

Returns:

  • (Boolean)


63
64
65
66
67
68
69
70
# File 'lib/abstractivator/enumerable_ext.rb', line 63

def uniq?
  seen = Set.new
  each_with_index do |x, i|
    seen << (block_given? ? yield(x) : x)
    return false if seen.size < i + 1
  end
  true
end

#unique_by(&block) ⇒ Object



117
118
119
# File 'lib/abstractivator/enumerable_ext.rb', line 117

def unique_by(&block)
  self.group_by(&block).map { |_, vs| vs.first }
end