b-lazy 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/b-lazy.rb +80 -35
- metadata +2 -2
data/lib/b-lazy.rb
CHANGED
@@ -18,6 +18,16 @@ class Enumerator
|
|
18
18
|
rescue StopIteration
|
19
19
|
true
|
20
20
|
end
|
21
|
+
|
22
|
+
|
23
|
+
def grab(n)
|
24
|
+
retval = []
|
25
|
+
begin
|
26
|
+
n.times{retval << self.next}
|
27
|
+
rescue StopIteration
|
28
|
+
end
|
29
|
+
retval
|
30
|
+
end
|
21
31
|
|
22
32
|
end
|
23
33
|
|
@@ -65,12 +75,15 @@ module Enumerable
|
|
65
75
|
end
|
66
76
|
end
|
67
77
|
end
|
78
|
+
|
79
|
+
|
80
|
+
|
68
81
|
|
69
82
|
|
70
83
|
# Start as soon as the condition becomes true
|
71
84
|
def start_when(&blk)
|
72
85
|
Enumerator.new do |out|
|
73
|
-
s = self.
|
86
|
+
s = self.ensure_enum
|
74
87
|
loop do
|
75
88
|
break if blk.call(s.peek)
|
76
89
|
s.next
|
@@ -86,7 +99,7 @@ module Enumerable
|
|
86
99
|
# Start one element after the condition becomes true
|
87
100
|
def start_after(&blk)
|
88
101
|
Enumerator.new do |out|
|
89
|
-
s = self.
|
102
|
+
s = self.ensure_enum
|
90
103
|
loop do
|
91
104
|
break if blk.call(s.next)
|
92
105
|
end
|
@@ -100,7 +113,7 @@ module Enumerable
|
|
100
113
|
|
101
114
|
# Continue as long as the condition is true
|
102
115
|
def do_while(&blk)
|
103
|
-
s = self.
|
116
|
+
s = self.ensure_enum
|
104
117
|
Enumerator.new do |out|
|
105
118
|
while s.has_next?
|
106
119
|
break unless blk.call(s.peek)
|
@@ -112,7 +125,7 @@ module Enumerable
|
|
112
125
|
|
113
126
|
# Keep iterating until the condition becomes true
|
114
127
|
def do_until(&blk)
|
115
|
-
s = self.
|
128
|
+
s = self.ensure_enum
|
116
129
|
Enumerator.new do |out|
|
117
130
|
until s.empty?
|
118
131
|
break if blk.call(s.peek)
|
@@ -126,7 +139,7 @@ module Enumerable
|
|
126
139
|
# Returns all elements up to and including the element
|
127
140
|
# the causes the condition to become true.
|
128
141
|
def stop_when(&blk)
|
129
|
-
s = self.
|
142
|
+
s = self.ensure_enum
|
130
143
|
Enumerator.new do |out|
|
131
144
|
while s.has_next?
|
132
145
|
out.yield s.peek
|
@@ -138,24 +151,23 @@ module Enumerable
|
|
138
151
|
|
139
152
|
def skip(n = 1)
|
140
153
|
Enumerator.new do |out|
|
141
|
-
s = self.
|
154
|
+
s = self.ensure_enum
|
142
155
|
begin
|
143
156
|
n.times {s.next}
|
144
157
|
loop do
|
145
158
|
out.yield s.next
|
146
159
|
end
|
160
|
+
rescue StopIteration
|
147
161
|
end
|
148
162
|
end
|
149
163
|
end
|
150
164
|
|
151
165
|
|
152
|
-
|
153
|
-
|
154
166
|
def cons()
|
155
167
|
Enumerator.new do |out|
|
156
|
-
s = self.
|
168
|
+
s = self.ensure_enum
|
157
169
|
loop do
|
158
|
-
items = s.next.
|
170
|
+
items = s.next.ensure_enum
|
159
171
|
loop do
|
160
172
|
out.yield items.next
|
161
173
|
end
|
@@ -172,38 +184,71 @@ module Enumerable
|
|
172
184
|
# one may hold an infinite number of items
|
173
185
|
def weave()
|
174
186
|
Enumerator.new do |out|
|
175
|
-
|
176
|
-
enums = []
|
177
|
-
|
187
|
+
enums = self.ensure_enum.lmap(&:ensure_enum)
|
178
188
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
enums << e
|
184
|
-
out.yield e.next
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
# Now all the enumerators have been collected into an Array.
|
191
|
-
# Henceforth, we'll iterate through this Array
|
192
|
-
until enums.empty?
|
193
|
-
next_enums = []
|
194
|
-
enums.each do |e|
|
195
|
-
if e.has_next?
|
196
|
-
next_enums << e
|
197
|
-
out.yield e.next
|
198
|
-
end
|
199
|
-
end
|
200
|
-
enums = next_enums
|
189
|
+
while enums.has_next? do
|
190
|
+
# We to_a each iteration to avoid creating a huge
|
191
|
+
# Enumerator stack.
|
192
|
+
enums = enums.lselect{|e| e.has_next?}.touch{|e| out.yield e.next}.to_a.ensure_enum
|
201
193
|
end
|
194
|
+
end
|
195
|
+
end
|
202
196
|
|
197
|
+
|
198
|
+
def diagonalize()
|
199
|
+
Enumerator.new do |out|
|
200
|
+
s = self.ensure_enum
|
201
|
+
enums = []
|
202
|
+
while s.has_next? do
|
203
|
+
enums.unshift s.next.ensure_enum
|
204
|
+
enums = enums.lselect{|e| e.has_next?}.touch{|e| out.yield e.next}.to_a
|
205
|
+
end
|
206
|
+
|
207
|
+
# Nothing else in s. Just weave the remaining elements
|
208
|
+
enums.weave.each{|x| out.yield x}
|
203
209
|
end
|
204
210
|
end
|
205
211
|
|
206
212
|
|
207
213
|
|
214
|
+
def ltranspose()
|
215
|
+
Enumerator.new do |out|
|
216
|
+
catch(:nothing_to_do) do
|
217
|
+
# If any Enumerable is empty, then yield nothing
|
218
|
+
enums = self.lmap{|e| e.ensure_enum}.
|
219
|
+
touch{|e| throw :nothing_to_do if e.empty?}.
|
220
|
+
to_a
|
221
|
+
|
222
|
+
loop do
|
223
|
+
out.yield enums.map{|e| e.next}
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
def groups_of(n)
|
231
|
+
Enumerator.new do |out|
|
232
|
+
s = self.ensure_enum
|
233
|
+
while s.has_next?
|
234
|
+
out.yield s.grab(n)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
# When #to_enum is called on an Enumerator, it creates a copy
|
242
|
+
# and rewinds it (when possible). Unfortunately, this is
|
243
|
+
# not actually the behavior that we want; we just want to make
|
244
|
+
# sure that we're operating on an Enumerator. So, this method
|
245
|
+
# calls #to_enum only if it is necessary.
|
246
|
+
def ensure_enum()
|
247
|
+
if self.kind_of? Enumerator
|
248
|
+
self
|
249
|
+
else
|
250
|
+
self.to_enum
|
251
|
+
end
|
252
|
+
end
|
208
253
|
|
209
254
|
end
|