Module: Enumerable
- Included in:
- Browser::Cache, ObjectSpace, Trie
- Defined in:
- lib/epitools/core_ext/enumerable.rb
Instance Method Summary collapse
-
#*(other) ⇒ Object
Multiplies this Enumerable by something.
-
#**(n) ⇒ Object
Multiplies this Enumerable by itself ‘n` times.
-
#average ⇒ Object
Average the elements.
-
#blank? ⇒ Boolean
‘true’ if the Enumerable has no elements.
-
#combination(*args, &block) ⇒ Object
See: See Array#combination.
-
#counts ⇒ Object
(also: #count_by, #group_counts)
Counts how many instances of each object are in the collection, returning a hash.
-
#cross_product(other) ⇒ Object
(also: #cross)
Same behaviour as Enumerator#cross_product.
-
#foldl(methodname = nil, &block) ⇒ Object
Identical to “reduce” in ruby1.9 (or foldl in haskell.).
-
#group_neighbours_by(&block) ⇒ Object
(also: #group_neighbors_by)
Associative grouping; groups all elements who share something in common with each other.
-
#groups ⇒ Object
(also: #grouped)
group_by the elements themselves.
-
#map_recursively(max_depth = nil, current_depth = 0, parent = nil, &block) ⇒ Object
(also: #deep_map, #recursive_map, #map_recursive)
The same as “map”, except that if an element is an Array or Enumerable, map is called recursively on that element.
-
#permutation(*args, &block) ⇒ Object
See: Array#permutation.
-
#powerset ⇒ Object
Returns the powerset of the Enumerable.
- #reverse_each ⇒ Object
-
#select_recursively(max_depth = nil, current_depth = 0, parent = nil, &block) ⇒ Object
(also: #deep_select, #recursive_select, #select_recursive)
The same as “select”, except that if an element is an Array or Enumerable, select is called recursively on that element.
-
#skip(n) ⇒ Object
Skip the first n elements and return an Enumerator for the rest, or pass them in succession to the block, if given.
-
#split_after(matcher = nil, options = {}, &block) ⇒ Object
Split the array into chunks, cutting between the matched element and the next element.
-
#split_at(matcher = nil, options = {}, &block) ⇒ Object
Split this enumerable into chunks, given some boundary condition.
-
#split_before(matcher = nil, options = {}, &block) ⇒ Object
Split the array into chunks, cutting before each matched element.
-
#split_between(&block) ⇒ Object
(also: #cut_between)
Split the array into chunks, cutting between two elements.
-
#sum(&block) ⇒ Object
(also: #sum_by)
Sum the elements.
-
#to_iter ⇒ Object
(also: #iter)
Convert the array into a stable iterator (Iter) object.
-
#uniq ⇒ Object
Lazily enumerate unique elements (WARNING: This can cause an infinite loop if you enumerate over a cycle, since it will keep reading the input until it finds a unique element).
-
#unzip ⇒ Object
Does the opposite of #zip – converts [ [:a, 1], [:b, 2] ] to [ [:a, :b], [1, 2] ].
Instance Method Details
#*(other) ⇒ Object
Multiplies this Enumerable by something. (Same behaviour as Enumerator#*)
411 412 413 414 415 416 417 418 |
# File 'lib/epitools/core_ext/enumerable.rb', line 411 def *(other) case other when Integer, String to_enum * other when Enumerable to_enum.cross_product(other) end end |
#**(n) ⇒ Object
Multiplies this Enumerable by itself ‘n` times.
423 424 425 |
# File 'lib/epitools/core_ext/enumerable.rb', line 423 def **(n) [self].cycle(n).reduce(:*) end |
#average ⇒ Object
Average the elements
187 188 189 190 191 192 193 194 |
# File 'lib/epitools/core_ext/enumerable.rb', line 187 def average count = 0 sum = 0 each { |e| count += 1; sum += e } sum / count.to_f end |
#blank? ⇒ Boolean
‘true’ if the Enumerable has no elements
6 7 8 |
# File 'lib/epitools/core_ext/enumerable.rb', line 6 def blank? not any? end |
#combination(*args, &block) ⇒ Object
See: See Array#combination
319 320 321 |
# File 'lib/epitools/core_ext/enumerable.rb', line 319 def combination(*args, &block) to_a.combination(*args, &block) end |
#counts ⇒ Object Also known as: count_by, group_counts
Counts how many instances of each object are in the collection, returning a hash. (Also optionally takes a block.)
eg: [:a, :b, :c, :c, :c, :c].counts #=> :b=>1, :c=>4
388 389 390 391 392 393 394 395 396 |
# File 'lib/epitools/core_ext/enumerable.rb', line 388 def counts h = Hash.of_integers if block_given? each { |x| h[yield x] += 1 } else each { |x| h[x] += 1 } end h end |
#cross_product(other) ⇒ Object Also known as: cross
Same behaviour as Enumerator#cross_product
430 431 432 |
# File 'lib/epitools/core_ext/enumerable.rb', line 430 def cross_product(other) to_enum.cross_product(other) end |
#foldl(methodname = nil, &block) ⇒ Object
Identical to “reduce” in ruby1.9 (or foldl in haskell.)
Example:
array.foldl{|a,b| a + b } == array[1..-1].inject(array[0]){|a,b| a + b }
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/epitools/core_ext/enumerable.rb', line 276 def foldl(methodname=nil, &block) result = nil raise "Error: pass a parameter OR a block, not both!" unless !!methodname ^ block_given? if methodname each_with_index do |e,i| if i == 0 result = e next end result = result.send(methodname, e) end else each_with_index do |e,i| if i == 0 result = e next end result = block.call(result, e) end end result end |
#group_neighbours_by(&block) ⇒ Object Also known as: group_neighbors_by
Associative grouping; groups all elements who share something in common with each other. You supply a block which takes two elements, and have it return true if they are “neighbours” (eg: belong in the same group).
Example:
[1,2,5,6].group_neighbours_by { |a,b| b-a <= 1 } #=> [ [1,2], [5,6] ]
(Note: This is a very fast one-pass algorithm – therefore, the groups must be pre-sorted.)
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/epitools/core_ext/enumerable.rb', line 356 def group_neighbours_by(&block) result = [] cluster = [first] each_cons(2) do |a,b| if yield(a,b) cluster << b else result << cluster cluster = [b] end end result << cluster if cluster.any? result end |
#groups ⇒ Object Also known as: grouped
group_by the elements themselves
403 404 405 |
# File 'lib/epitools/core_ext/enumerable.rb', line 403 def groups group_by(&:self) end |
#map_recursively(max_depth = nil, current_depth = 0, parent = nil, &block) ⇒ Object Also known as: deep_map, recursive_map, map_recursive
The same as “map”, except that if an element is an Array or Enumerable, map is called recursively on that element. (Hashes are ignored because of the complications of block arguments and return values.)
Example:
[ [1,2], [3,4] ].deep_map{|e| e ** 2 } #=> [ [1,4], [9,16] ]
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/epitools/core_ext/enumerable.rb', line 217 def map_recursively(max_depth=nil, current_depth=0, parent=nil, &block) return self if max_depth and (current_depth > max_depth) map do |obj| if obj == parent # infinite loop scenario! yield obj else case obj when String, Hash yield obj when Enumerable obj.map_recursively(max_depth, current_depth+1, self, &block) else yield obj end end end end |
#permutation(*args, &block) ⇒ Object
See: Array#permutation
312 313 314 |
# File 'lib/epitools/core_ext/enumerable.rb', line 312 def permutation(*args, &block) to_a.permutation(*args, &block) end |
#powerset ⇒ Object
Returns the powerset of the Enumerable
Example:
[1,2].powerset #=> [[], [1], [2], [1, 2]]
329 330 331 332 333 334 335 336 |
# File 'lib/epitools/core_ext/enumerable.rb', line 329 def powerset return to_enum(:powerset) unless block_given? a = to_a (0...2**a.size).each do |bitmask| # the bit pattern of the numbers from 0..2^(elements)-1 can be used to select the elements of the set... yield a.select.with_index { |e, i| bitmask[i] == 1 } end end |
#reverse_each ⇒ Object
43 44 45 |
# File 'lib/epitools/core_ext/enumerable.rb', line 43 def reverse_each to_a.to_enum(:reverse_each) end |
#select_recursively(max_depth = nil, current_depth = 0, parent = nil, &block) ⇒ Object Also known as: deep_select, recursive_select, select_recursive
The same as “select”, except that if an element is an Array or Enumerable, select is called recursively on that element.
Example:
[ [1,2], [3,4] ].select_recursively{|e| e % 2 == 0 } #=> [ [2], [4] ]
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/epitools/core_ext/enumerable.rb', line 247 def select_recursively(max_depth=nil, current_depth=0, parent=nil, &block) return self if max_depth and (current_depth > max_depth) map do |obj| if obj == parent # infinite loop scenario! obj if yield obj else case obj when String, Hash obj if yield obj when Enumerable obj.deep_select(max_depth, current_depth+1, self, &block) else obj if yield obj end end end.compact end |
#skip(n) ⇒ Object
Skip the first n elements and return an Enumerator for the rest, or pass them in succession to the block, if given. This is like “drop”, but returns an enumerator instead of converting the whole thing to an array.
25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/epitools/core_ext/enumerable.rb', line 25 def skip(n) if block_given? each do |x| if n > 0 n -= 1 else yield x end end else to_enum(:skip, n) end end |
#split_after(matcher = nil, options = {}, &block) ⇒ Object
Split the array into chunks, cutting between the matched element and the next element.
Example:
[1,2,3,4].split_after{|e| e == 3 } #=> [ [1,2,3], [4] ]
128 129 130 131 132 |
# File 'lib/epitools/core_ext/enumerable.rb', line 128 def split_after(matcher=nil, ={}, &block) [:after] ||= true [:include_boundary] ||= true split_at(matcher, , &block) end |
#split_at(matcher = nil, options = {}, &block) ⇒ Object
Split this enumerable into chunks, given some boundary condition. (Returns an array of arrays.)
Options:
:include_boundary => true #=> include the element that you're splitting at in the results
(default: false)
:after => true #=> split after the matched element (only has an effect when used with :include_boundary)
(default: false)
:once => flase #=> only perform one split (default: false)
Examples:
[1,2,3,4,5].split{ |e| e == 3 }
#=> [ [1,2], [4,5] ]
"hello\n\nthere\n".each_line.split_at("\n").to_a
#=> [ ["hello\n"], ["there\n"] ]
[1,2,3,4,5].split(:include_boundary=>true) { |e| e == 3 }
#=> [ [1,2], [3,4,5] ]
chapters = File.read("ebook.txt").split(/Chapter \d+/, :include_boundary=>true)
#=> [ ["Chapter 1", ...], ["Chapter 2", ...], etc. ]
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/epitools/core_ext/enumerable.rb', line 71 def split_at(matcher=nil, ={}, &block) include_boundary = [:include_boundary] || false if matcher.nil? boundary_test_proc = block else if matcher.is_a? Regexp boundary_test_proc = proc { |element| element =~ matcher } else boundary_test_proc = proc { |element| element == matcher } end end Enumerator.new do |yielder| current_chunk = [] splits = 0 max_splits = [:once] == true ? 1 : [:max_splits] each do |e| if boundary_test_proc.call(e) and (max_splits == nil or splits < max_splits) if current_chunk.empty? and not include_boundary next # hit 2 boundaries in a row... just keep moving, people! end if [:after] # split after boundary current_chunk << e if include_boundary # include the boundary, if necessary yielder << current_chunk # shift everything after the boundary into the resultset current_chunk = [] # start a new result else # split before boundary yielder << current_chunk # shift before the boundary into the resultset current_chunk = [] # start a new result current_chunk << e if include_boundary # include the boundary, if necessary end splits += 1 else current_chunk << e end end yielder << current_chunk if current_chunk.any? end end |
#split_before(matcher = nil, options = {}, &block) ⇒ Object
Split the array into chunks, cutting before each matched element.
Example:
[1,2,3,4].split_before{|e| e == 3 } #=> [ [1,2], [3,4] ]
140 141 142 143 |
# File 'lib/epitools/core_ext/enumerable.rb', line 140 def split_before(matcher=nil, ={}, &block) [:include_boundary] ||= true split_at(matcher, , &block) end |
#split_between(&block) ⇒ Object Also known as: cut_between
Split the array into chunks, cutting between two elements.
Example:
[1,1,2,2].split_between{|a,b| a != b } #=> [ [1,1], [2,2] ]
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/epitools/core_ext/enumerable.rb', line 151 def split_between(&block) Enumerator.new do |yielder| current = [] last = nil each_cons(2) do |a,b| current << a if yield(a,b) yielder << current current = [] end last = b end current << last unless last.nil? yielder << current end end |
#sum(&block) ⇒ Object Also known as: sum_by
Sum the elements
175 176 177 178 179 180 181 |
# File 'lib/epitools/core_ext/enumerable.rb', line 175 def sum(&block) if block_given? map(&block).reduce(:+) else reduce(:+) end end |
#to_iter ⇒ Object Also known as: iter
Convert the array into a stable iterator (Iter) object.
377 378 379 |
# File 'lib/epitools/core_ext/enumerable.rb', line 377 def to_iter Iter.new(to_a) end |
#uniq ⇒ Object
Lazily enumerate unique elements (WARNING: This can cause an infinite loop if you enumerate over a cycle,
since it will keep reading the input until it finds a unique element)
201 202 203 204 205 206 207 |
# File 'lib/epitools/core_ext/enumerable.rb', line 201 def uniq already_seen = Set.new Enumerator::Lazy.new(self) do |yielder, value| yielder << value if already_seen.add?(value) end end |
#unzip ⇒ Object
Does the opposite of #zip – converts [ [:a, 1], [:b, 2] ] to [ [:a, :b], [1, 2] ]
341 342 343 344 |
# File 'lib/epitools/core_ext/enumerable.rb', line 341 def unzip # TODO: make it work for arrays containing uneven-length contents to_a.transpose end |