b-lazy 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|