b-lazy 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/b-lazy.rb +88 -20
- metadata +2 -2
data/lib/b-lazy.rb
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
# few convenient methods that can simplify looping constructs.
|
6
6
|
class Enumerator
|
7
7
|
|
8
|
+
# If the Enumerator is empty, then return false. Otherwise,
|
9
|
+
# return true.
|
8
10
|
def has_next?
|
9
11
|
peek
|
10
12
|
true
|
@@ -12,6 +14,9 @@ class Enumerator
|
|
12
14
|
false
|
13
15
|
end
|
14
16
|
|
17
|
+
|
18
|
+
# If the Enumerator is empty, then return true. Otherwise,
|
19
|
+
# return false.
|
15
20
|
def empty?
|
16
21
|
peek
|
17
22
|
false
|
@@ -20,6 +25,8 @@ class Enumerator
|
|
20
25
|
end
|
21
26
|
|
22
27
|
|
28
|
+
# This is similar to the #take method, except that it
|
29
|
+
# actually moves the Enumerator ahead n after each call.
|
23
30
|
def grab(n)
|
24
31
|
retval = []
|
25
32
|
begin
|
@@ -46,10 +53,14 @@ module Enumerable
|
|
46
53
|
end
|
47
54
|
|
48
55
|
|
49
|
-
# This is similar to the tap method
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
56
|
+
# This is similar to the tap method, but it operates on
|
57
|
+
# each element of the Enumerator as it passes through.
|
58
|
+
# This is useful for many things, such as:
|
59
|
+
#
|
60
|
+
# 1. Examining the state of the element
|
61
|
+
# 2. Logging
|
62
|
+
# 3. Modifying the element's state
|
63
|
+
# 4. Recording interim values
|
53
64
|
def touch(&blk)
|
54
65
|
Enumerator.new do |out|
|
55
66
|
self.each do |x|
|
@@ -60,6 +71,8 @@ module Enumerable
|
|
60
71
|
end
|
61
72
|
|
62
73
|
|
74
|
+
# This is the same as the #select method except that it
|
75
|
+
# operates lazily.
|
63
76
|
def lselect(&blk)
|
64
77
|
Enumerator.new do |out|
|
65
78
|
self.each do |i|
|
@@ -68,6 +81,9 @@ module Enumerable
|
|
68
81
|
end
|
69
82
|
end
|
70
83
|
|
84
|
+
|
85
|
+
# This is the same as the #reject method except that it
|
86
|
+
# operates lazily.
|
71
87
|
def lreject(&blk)
|
72
88
|
Enumerator.new do |out|
|
73
89
|
self.each do |i|
|
@@ -75,12 +91,9 @@ module Enumerable
|
|
75
91
|
end
|
76
92
|
end
|
77
93
|
end
|
78
|
-
|
79
|
-
|
80
94
|
|
81
95
|
|
82
|
-
|
83
|
-
# Start as soon as the condition becomes true
|
96
|
+
# Begins yielding values as soon as the condition becomes true.
|
84
97
|
def start_when(&blk)
|
85
98
|
Enumerator.new do |out|
|
86
99
|
s = self.ensure_enum
|
@@ -149,6 +162,8 @@ module Enumerable
|
|
149
162
|
end
|
150
163
|
|
151
164
|
|
165
|
+
# Skips the specified number of elements. Note that this
|
166
|
+
# method does not complain if the Enumerator is empty.
|
152
167
|
def skip(n = 1)
|
153
168
|
Enumerator.new do |out|
|
154
169
|
s = self.ensure_enum
|
@@ -163,6 +178,12 @@ module Enumerable
|
|
163
178
|
end
|
164
179
|
|
165
180
|
|
181
|
+
# In Java-speak, we would say this method operates on
|
182
|
+
# Enumerable<Enumerable<?>> . It concatenates the values
|
183
|
+
# of each nested Enumerable and produces one Enumerable that
|
184
|
+
# contains all of the values. For example:
|
185
|
+
#
|
186
|
+
# [[1, 2, 3], [4, 5]].cons.to_a -> [1, 2, 3, 4, 5]
|
166
187
|
def cons()
|
167
188
|
Enumerator.new do |out|
|
168
189
|
s = self.ensure_enum
|
@@ -176,12 +197,11 @@ module Enumerable
|
|
176
197
|
end
|
177
198
|
|
178
199
|
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
# one may hold an infinite number of items
|
200
|
+
# This is similar to cons, but it
|
201
|
+
# instead takes the first item from each enumerator,
|
202
|
+
# then the second item, etc. This can be handy when
|
203
|
+
# you have a finite number of enumerators, but each
|
204
|
+
# one may hold an infinite number of items
|
185
205
|
def weave()
|
186
206
|
Enumerator.new do |out|
|
187
207
|
enums = self.ensure_enum.lmap(&:ensure_enum)
|
@@ -195,6 +215,10 @@ module Enumerable
|
|
195
215
|
end
|
196
216
|
|
197
217
|
|
218
|
+
# If you have an infinite number of Enumerators, and each of these
|
219
|
+
# have an infinite number of elements, then you should iterate over
|
220
|
+
# them using Cantor's diagonalization technique. As t -> infinity,
|
221
|
+
# you will examine all elements from all Enumerators.
|
198
222
|
def diagonalize()
|
199
223
|
Enumerator.new do |out|
|
200
224
|
s = self.ensure_enum
|
@@ -210,7 +234,27 @@ module Enumerable
|
|
210
234
|
end
|
211
235
|
|
212
236
|
|
213
|
-
|
237
|
+
# Randomizes the order in which the elements are yielded. Since
|
238
|
+
# this is done in a lazy fashion, it is not as random as actually
|
239
|
+
# shuffling the entire list.
|
240
|
+
def randomly(n = 8)
|
241
|
+
Enumerator.new do |out|
|
242
|
+
s = self.ensure_enum
|
243
|
+
pool = s.grab(n)
|
244
|
+
while s.has_next?
|
245
|
+
index = rand(n)
|
246
|
+
out.yield pool[index]
|
247
|
+
pool[index] = s.next
|
248
|
+
end
|
249
|
+
pool.sort_by{rand}.each{|x| out.yield x}
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
# This is similar to Array's transpose method, but it can operate
|
255
|
+
# on any Enumerable. Additionally, it stops as soon as the first
|
256
|
+
# Enumerable is exhausted (rather than setting the missing values
|
257
|
+
# equal to nil).
|
214
258
|
def ltranspose()
|
215
259
|
Enumerator.new do |out|
|
216
260
|
catch(:nothing_to_do) do
|
@@ -227,15 +271,39 @@ module Enumerable
|
|
227
271
|
end
|
228
272
|
|
229
273
|
|
230
|
-
|
274
|
+
|
275
|
+
# Keeps repeating the same elements indefinitely.
|
276
|
+
def cycle()
|
231
277
|
Enumerator.new do |out|
|
232
|
-
|
233
|
-
|
234
|
-
|
278
|
+
values = self.touch{|x| out.yield x}.to_a
|
279
|
+
unless values.empty?
|
280
|
+
loop do
|
281
|
+
values.each{|x| out.yield x}
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
# This is a lazy version of the #product method. It returns
|
289
|
+
# all combinations of values from the provided Enumerators.
|
290
|
+
#
|
291
|
+
# Ex: [[1, 2], [3, 4]].lproduct.to_a -> [[1, 3], [1, 4], [2, 3], [2, 4]]
|
292
|
+
#def lproduct()
|
293
|
+
#
|
294
|
+
#end
|
295
|
+
|
296
|
+
|
297
|
+
# Repeats the same sequence of elements n times.
|
298
|
+
def repeat(n)
|
299
|
+
n = n.to_i
|
300
|
+
Enumerator.new do |out|
|
301
|
+
if n >= 1
|
302
|
+
values = self.touch{|x| out.yield x}.to_a
|
303
|
+
(n - 1).times{ values.each{|x| out.yield x} }
|
235
304
|
end
|
236
305
|
end
|
237
306
|
end
|
238
|
-
|
239
307
|
|
240
308
|
|
241
309
|
# When #to_enum is called on an Enumerator, it creates a copy
|