b-lazy 0.0.3 → 0.0.4
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 +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
|