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.
Files changed (2) hide show
  1. data/lib/b-lazy.rb +80 -35
  2. 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.to_enum
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.to_enum
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.to_enum
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.to_enum
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.to_enum
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.to_enum
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.to_enum
168
+ s = self.ensure_enum
157
169
  loop do
158
- items = s.next.to_enum
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
- s = self.to_enum
176
- enums = []
177
-
187
+ enums = self.ensure_enum.lmap(&:ensure_enum)
178
188
 
179
- # The first time through, we will gradually collect all
180
- # of self's enumerators into an Array.
181
- s.lmap{|e| e.to_enum}.each do |e|
182
- if e.has_next?
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
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 3
9
- version: 0.0.3
8
+ - 4
9
+ version: 0.0.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Lauber