Module: Enumerable
- Defined in:
- lib/sixarm_ruby_ramp/enumerable.rb,
lib/sixarm_ruby_ramp/enumerable/map.rb,
lib/sixarm_ruby_ramp/enumerable/each.rb,
lib/sixarm_ruby_ramp/enumerable/nitems.rb,
lib/sixarm_ruby_ramp/enumerable/select.rb
Class Method Summary collapse
-
.cartesian_product(*enums) ⇒ Array
This is the fastest implementation we have found.
Instance Method Summary collapse
-
#bisect ⇒ Array<Array<Object>] an array of two arrays: the first array is the elements for which block is true, the second array is the elements for which block is false or nil.
Array<Array<Object>] an array of two arrays: the first array is the elements for which block is true, the second array is the elements for which block is false or nil.
-
#cartesian_product(*enums) ⇒ Object
Calculate the cartesian product.
-
#each_at(filter) ⇒ Object
Get each element at a given index or indices.
-
#each_at_normalize_filter(filter) ⇒ Object
Normalize the filter to make it respond to #each and #include?.
-
#each_at_strategy_with_optimization_max(filter) ⇒ Object
Implement #each_at by using a strategy with full optimization.
-
#each_at_strategy_with_optimization_min(filter) ⇒ Object
Implement #each_at by using a strategy with some optimization.
-
#each_at_strategy_with_optimization_off(filter) ⇒ Object
Implement #each_at by using a strategy with no optimization.
-
#hash_by ⇒ Hash<Object,Object>
Convert the enumerable to a hash by mapping each item to a pair [item, new item].
-
#index_by ⇒ Hash<Integer,Object>
Convert the enumerable to a hash by mapping each item to a pair [index ,item].
-
#intersect?(enum) ⇒ Boolean
A developer may want to optimize this implementation for other classes, such as detecting whether a range intersects another range simply by comparing the ranges’ min/max values.
-
#join(*op) ⇒ String
Shortcut to Array#join to concatenate the items into a string.
-
#map_id ⇒ Enumerable<Object>
Map each item => item.id.
-
#map_to_a ⇒ Enumberable<Array<Object>>
Map each item => item.to_a.
-
#map_to_f ⇒ Enumerable<Float>
Map each item => item.to_f.
-
#map_to_i ⇒ Enumerable<Integer>
Map each item => item.to_i.
-
#map_to_s ⇒ Enumerable<String>
Map each item => item.to_s.
-
#map_to_sym ⇒ Enumerable<Symbol>
Map each item => item.to_sym.
-
#map_with_index ⇒ Enumerable<Object>
Map each item and its index => a new output.
-
#mutex? ⇒ Boolean
Boolean true iff block is not false or nil, zero or one time.
-
#nitems?(n) ⇒ Boolean
True iff the block is not false or nil num times.
-
#nitems_until ⇒ Integer
The number of leading elements for which block is false.
-
#nitems_while ⇒ Integer
The number of leading elements for which block is not false or nil.
-
#nitems_with_index ⇒ Integer
Calls block with two arguments, the item and its index, for each item in enum.
-
#power_set ⇒ Array<Array<Object>>
Calculate the power set.
-
#select_until ⇒ Array<Object>
The leading elements for which block is falsey.
-
#select_while ⇒ Array<Object>
The leading elements for which block is truthy.
-
#select_with_index ⇒ Array<Object> the leading elements for which block is truthy.
Calls block with two arguments, the item and its index, for each item in enum.
- #to_h ⇒ Object
-
#to_h_merge ⇒ Hash<Object,Object>
Convert an enumerable to a hash and merge values.
Class Method Details
.cartesian_product(*enums) ⇒ Array
This is the fastest implementation we have found. It returns results in typical order.
For our benchmarks, we also compared these:
-
By William James, www.ruby-forum.com/topic/95519
-
By Brian Schröäer, blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/151857
318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 318 def self.cartesian_product(*enums) 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 |
Instance Method Details
#bisect ⇒ Array<Array<Object>] an array of two arrays: the first array is the elements for which block is true, the second array is the elements for which block is false or nil.
Returns Array<Array<Object>] an array of two arrays: the first array is the elements for which block is true, the second array is the elements for which block is false or nil.
165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 165 def bisect accept=[] reject=[] each{|item| if yield(item) accept << item else reject << item end } return accept,reject end |
#cartesian_product(*enums) ⇒ Object
Calculate the cartesian product.
334 335 336 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 334 def cartesian_product(*enums) Enumerable.cartesian_product(self,*enums) end |
#each_at(filter) ⇒ Object
Get each element at a given index or indices.
Example: use an index.
["a", "b", "c", "d", "e"].each_at(1)
#=> "b"
Example: use an index that is negative when size is known.
["a", "b", "c", "d", "e"].each_at(-1)
=> "e"
Example: use a range.
["a", "b", "c", "d", "e"].each_at(1..3)
=> "b", "c", "d"
Example: use a range that has negatives when size is known.
["a", "b", "c", "d", "e"].each_at(-3..-1)
=> "c", "d", "e"
Example: use any object that responds to #each or #include?.
["a", "b", "c", "d", "e"].each_at([4, 2, -2])
=> "e", "c", "d"
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/sixarm_ruby_ramp/enumerable/each.rb', line 31 def each_at(filter) filter, optimize_for_whole_numbers = each_at_normalize_filter(filter) # Handle variations. # # Can we call self#at? # # * Yes: look up a self element by index. # * No: iterate on self, comparing the loop count to filter target. # # Can we call filter#each? # # * Yes: iterate on the filter elements. # * No: iterate on self, comparing the loop count to filter#include? # # Can we optimize for whole numbers? # # * Yes: we know that all filter targets are whole numbers. # * No: we must convert the filter target to an index size each time. # if self.respond_to?(:at) && filter.respond_to?(:each) if optimize_for_whole_numbers # each_at_strategy_with_self_at_and_filter_each_and_whole_numbers(filter) filter.each{|i| yield(at(i)) } else # each_at_strategy_with_self_at_and_filter_each(filter) filter.each{|i| yield(at(i >= 0 ? i : i + self.size)) } end elsif filter.respond_to?(:include?) # each_at_strategy_with_count(filter) i = 0 s = respond_to?(:size) ? size : nil each{|e| yield(e) if (filter.include?(i) || (size && filter.include(i - size))) i += 1 } else raise ArgumentError end end |
#each_at_normalize_filter(filter) ⇒ Object
Normalize the filter to make it respond to #each and #include?.
If we can guarantee the filter is all whole numbers, then subsequent method calls can optimize the index lookup, by looking for the whole numbers instead of negative numbers.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/sixarm_ruby_ramp/enumerable/each.rb', line 132 def each_at_normalize_filter(filter) case filter when Numeric return [filter.to_i], filter >= 0 when Range if filter.first < 0 || filter.last < 0 min = filter.first.to_i; min += size if min < 0 max = filter.last.to_i; max += size if max < 0 max -= 1 if filter.exclude_end? filter = min..max end return filter, true else return filter, false end end |
#each_at_strategy_with_optimization_max(filter) ⇒ Object
Implement #each_at by using a strategy with full optimization.
When #each_at tests that both self#at is available and filter#each is available, and can test that all indexes are whole numbers, then #each_at calls this strategy.
120 121 122 123 124 |
# File 'lib/sixarm_ruby_ramp/enumerable/each.rb', line 120 def each_at_strategy_with_optimization_max(filter) filter.each{|i| yield(at(i)) } end |
#each_at_strategy_with_optimization_min(filter) ⇒ Object
Implement #each_at by using a strategy with some optimization.
When #each_at tests that both self#at is available and filter#each is available, yet cannot test that all indexes are whole numbers, then #each_at calls this strategy.
108 109 110 111 112 |
# File 'lib/sixarm_ruby_ramp/enumerable/each.rb', line 108 def each_at_strategy_with_optimization_min(filter) filter.each{|i| yield(at(i >= 0 ? i : i + self.size)) } end |
#each_at_strategy_with_optimization_off(filter) ⇒ Object
Implement #each_at by using a strategy with no optimization.
When #each_at tests that either self#at is unavailable or filter#each is unavailable, then #each_at calls this strategy.
This strategy uses a loop counter and iteration on the self elements, and each iteration, test whether the counter is in the filter.
This strategy is the slowest, and for the worst-case need. This strategy is rarely needed in the wild.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/sixarm_ruby_ramp/enumerable/each.rb', line 87 def each_at_strategy_with_optimization_off(filter) i = 0 if respond_to?(:size) each{|e| yield(e) if (filter.include?(i) || (size && filter.include?(i - size))) i += 1 } else each{|e| yield(e) if (filter.include?(i)) i += 1 } end end |
#hash_by ⇒ Hash<Object,Object>
Convert the enumerable to a hash by mapping each item to a pair [item, new item]
95 96 97 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 95 def hash_by map{|item| yield(item)}.to_h end |
#index_by ⇒ Hash<Integer,Object>
Convert the enumerable to a hash by mapping each item to a pair [index ,item]
Rails has this method.
From stackoverflow.com/questions/412771/cleanest-way-to-create-a-hash-from-an-array
80 81 82 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 80 def index_by inject({}) {|hash, elem| hash.merge!(yield(elem) => elem) } end |
#intersect?(enum) ⇒ Boolean
A developer may want to optimize this implementation for other classes, such as detecting whether a range intersects another range simply by comparing the ranges’ min/max values.
300 301 302 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 300 def intersect?(enum) return enum.any?{|item| self.include?(item)} end |
#join(*op) ⇒ String
Shortcut to Array#join to concatenate the items into a string
280 281 282 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 280 def join(*op) to_a.join(*op) end |
#map_id ⇒ Enumerable<Object>
Map each item => item.id
A typical use is to convert a list of ActiveRecord items to a list of id items.
This method is a faster way to get the same results as items.map(&:id)
16 17 18 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 16 def map_id map{|item| item.id} end |
#map_to_a ⇒ Enumberable<Array<Object>>
Map each item => item.to_a
This method is a faster way to get the same results as items.map(&:to_a)
30 31 32 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 30 def map_to_a map{|item| item.to_a} end |
#map_to_f ⇒ Enumerable<Float>
Map each item => item.to_f
A typical use is to convert a list of String items to a list of float items.
This method is a fast way to get the same results as items.map(&:to_f)
46 47 48 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 46 def map_to_f map{|item| item.to_f} end |
#map_to_i ⇒ Enumerable<Integer>
Map each item => item.to_i
A typical use is to convert a list of String items to a list of integer items.
This method is a fast way to get the same results as items.map(&:to_i)
62 63 64 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 62 def map_to_i map{|item| item.to_i} end |
#map_to_s ⇒ Enumerable<String>
Map each item => item.to_s
A typical use is to convert a list of Numeric items to a list of String items.
This method is a fast way to get the same results as items.map(&:to_s)
78 79 80 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 78 def map_to_s map{|item| item.to_s} end |
#map_to_sym ⇒ Enumerable<Symbol>
Map each item => item.to_sym
A typical use is to convert a list of Object items to a list of Symbol items.
This method is a fast way to get the same results as items.map(&:to_sym)
94 95 96 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 94 def map_to_sym map{|item| item.to_sym} end |
#map_with_index ⇒ Enumerable<Object>
Map each item and its index => a new output
109 110 111 112 |
# File 'lib/sixarm_ruby_ramp/enumerable/map.rb', line 109 def map_with_index index=-1 map{|item| index+=1; yield(item,index)} end |
#mutex? ⇒ Boolean
Returns boolean true iff block is not false or nil, zero or one time.
190 191 192 193 194 195 196 197 198 199 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 190 def mutex? num = 0 each{|item| if yield(item) num += 1 if num > 1 then return false end end } return true end |
#nitems?(n) ⇒ Boolean
Returns true iff the block is not false or nil num times.
213 214 215 216 217 218 219 220 221 222 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 213 def nitems?(n) num = 0 each{|item| if yield(item) num+=1 if num > n then return false end end } return num==n end |
#nitems_until ⇒ Integer
Returns the number of leading elements for which block is false.
242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 242 def nitems_until num = 0 each{|item| if yield(item) break else num+=1 end } return num end |
#nitems_while ⇒ Integer
Returns the number of leading elements for which block is not false or nil.
230 231 232 233 234 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 230 def nitems_while num = 0 each{|item| yield(item) ? (num+=1) : break} return num end |
#nitems_with_index ⇒ Integer
Calls block with two arguments, the item and its index, for each item in enum.
263 264 265 266 267 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 263 def nitems_with_index index = 0 each{|item| yield(item,index) ? (index+=1) : break} return index end |
#power_set ⇒ Array<Array<Object>>
Calculate the power set.
This implementation is from the blog post below:
350 351 352 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 350 def power_set inject([[]]){|c,y|r=[];c.each{|i|r<<i;r<<i+[y]};r} end |
#select_until ⇒ Array<Object>
Returns the leading elements for which block is falsey.
123 124 125 126 127 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 123 def select_until arr = [] each{|item| yield(item) ? break : (arr << item)} return arr end |
#select_while ⇒ Array<Object>
Returns the leading elements for which block is truthy.
111 112 113 114 115 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 111 def select_while arr = [] each{|item| yield(item) ? (arr << item) : break} return arr end |
#select_with_index ⇒ Array<Object> the leading elements for which block is truthy.
Calls block with two arguments, the item and its index, for each item in enum.
137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 137 def select_with_index index = 0 arr = [] each{|item| if yield(item,index) arr << item index+=1 else break end } return arr end |
#to_h ⇒ Object
22 23 24 25 26 27 28 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 22 def to_h hash={} each{|key,val| hash[key]=val } return hash end |
#to_h_merge ⇒ Hash<Object,Object>
Convert an enumerable to a hash and merge values.
If a key occurs more than once, then this will automatically merge the values to an array of the keys’ values.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/sixarm_ruby_ramp/enumerable.rb', line 46 def to_h_merge hash={} seen=Set.new each{|key,val| if hash.key? key if seen.include? key hash[key] << val else hash[key]=[hash[key]] hash[key] << val seen << key end else hash[key]=val end } return hash end |