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.
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