Commit | Line | Data |
---|---|---|
6a1aa64f DV |
1 | .. title:: MochiKit.Iter - itertools for JavaScript; iteration made HARD, and then easy |
2 | ||
3 | Name | |
4 | ==== | |
5 | ||
6 | MochiKit.Iter - itertools for JavaScript; iteration made HARD, and | |
7 | then easy | |
8 | ||
9 | ||
10 | Synopsis | |
11 | ======== | |
12 | ||
13 | :: | |
14 | ||
15 | ||
16 | theSum = sum(takewhile( | |
17 | partial(operator.gt, 10), | |
18 | imap( | |
19 | partial(operator.mul, 2), | |
20 | count() | |
21 | ) | |
22 | ) | |
23 | )); | |
24 | ||
25 | assert( theSum == (0 + 0 + 2 + 4 + 6 + 8) ); | |
26 | ||
27 | ||
28 | Description | |
29 | =========== | |
30 | ||
31 | All of the functional programming missing from | |
32 | :mochiref:`MochiKit.Base` lives here. The functionality in this module | |
33 | is largely inspired by Python's iteration protocol [1]_, and the | |
34 | itertools module [2]_. | |
35 | ||
36 | MochiKit.Iter defines a standard way to iterate over anything, that | |
37 | you can extend with :mochiref:`registerIterator`, or by implementing | |
38 | the ``.iter()`` or ``.__iterator__()`` (in MochiKit 1.4+) protocol. | |
39 | Iterators are lazy, so it can potentially be | |
40 | cheaper to build a filter chain of iterators than to build lots of | |
41 | intermediate arrays. Especially when the data set is very large, but | |
42 | the result is not. | |
43 | ||
44 | ||
45 | Dependencies | |
46 | ============ | |
47 | ||
48 | - :mochiref:`MochiKit.Base` | |
49 | ||
50 | ||
51 | Overview | |
52 | ======== | |
53 | ||
54 | Iteration for JavaScript | |
55 | ------------------------ | |
56 | ||
57 | The best overview right now is in my Iteration for JavaScript [3]_ | |
58 | blog entry. This information will migrate here eventually. | |
59 | ||
60 | API Reference | |
61 | ============= | |
62 | ||
63 | Errors | |
64 | ------ | |
65 | ||
66 | :mochidef:`StopIteration`: | |
67 | ||
68 | The singleton :mochiref:`MochiKit.Base.NamedError` that signifies | |
69 | the end of an iterator | |
70 | ||
71 | *Availability*: | |
72 | Available in MochiKit 1.3.1+ | |
73 | ||
74 | ||
75 | Functions | |
76 | --------- | |
77 | ||
78 | :mochidef:`applymap(fun, seq[, self])`: | |
79 | ||
80 | ``applymap(fun, seq)`` --> | |
81 | fun.apply(self, seq0), fun.apply(self, seq1), ... | |
82 | ||
83 | *Availability*: | |
84 | Available in MochiKit 1.3.1+ | |
85 | ||
86 | ||
87 | :mochidef:`chain(p, q[, ...])`: | |
88 | ||
89 | ``chain(p, q, ...)`` --> p0, p1, ... plast, q0, q1, ... | |
90 | ||
91 | *Availability*: | |
92 | Available in MochiKit 1.3.1+ | |
93 | ||
94 | ||
95 | :mochidef:`count(n=0)`: | |
96 | ||
97 | ``count(n=0)`` --> n, n + 1, n + 2, ... | |
98 | ||
99 | *Availability*: | |
100 | Available in MochiKit 1.3.1+ | |
101 | ||
102 | ||
103 | :mochidef:`cycle(p)`: | |
104 | ||
105 | ``cycle(p)`` --> p0, p1, ... plast, p0, p1, ... | |
106 | ||
107 | *Availability*: | |
108 | Available in MochiKit 1.3.1+ | |
109 | ||
110 | ||
111 | :mochidef:`dropwhile(pred, seq)`: | |
112 | ||
113 | ``dropwhile(pred, seq)`` --> seq[n], seq[n + 1], starting when | |
114 | pred(seq[n]) fails | |
115 | ||
116 | *Availability*: | |
117 | Available in MochiKit 1.3.1+ | |
118 | ||
119 | ||
120 | :mochidef:`every(iterable, func)`: | |
121 | ||
122 | Return ``true`` if ``func(item)`` is ``true`` for every item in | |
123 | ``iterable``. | |
124 | ||
125 | *Availability*: | |
126 | Available in MochiKit 1.3.1+ | |
127 | ||
128 | ||
129 | :mochidef:`exhaust(iterable)`: | |
130 | ||
131 | Exhausts an iterable without saving the results anywhere, like | |
132 | :mochiref:`list(iterable)` when you don't care what the output is. | |
133 | ||
134 | *Availability*: | |
135 | Available in MochiKit 1.3.1+ | |
136 | ||
137 | ||
138 | :mochidef:`forEach(iterable, func[, self])`: | |
139 | ||
140 | Call ``func`` for each item in ``iterable``, and don't save the | |
141 | results. | |
142 | ||
143 | *Availability*: | |
144 | Available in MochiKit 1.3.1+ | |
145 | ||
146 | ||
147 | :mochidef:`groupby(iterable[, keyfunc])`: | |
148 | ||
149 | Make an iterator that returns consecutive keys and groups from the | |
150 | iterable. The key is a function computing a key value for each | |
151 | element. If not specified or is None, key defaults to an identity | |
152 | function and returns the element unchanged. Generally, the | |
153 | iterable needs to already be sorted on the same key function. | |
154 | ||
155 | The returned group is itself an iterator that shares the | |
156 | underlying iterable with :mochiref:`groupby()`. Because the source | |
157 | is shared, when the groupby object is advanced, the previous group | |
158 | is no longer visible. So, if that data is needed later, it should | |
159 | be stored as an array:: | |
160 | ||
161 | var groups = []; | |
162 | var uniquekeys = []; | |
163 | forEach(groupby(data, keyfunc), function (key_group) { | |
164 | groups.push(list(key_group[1])); | |
165 | uniquekeys.push(key_group[0]); | |
166 | }); | |
167 | ||
168 | As a convenience, :mochiref:`groupby_as_array()` is provided to | |
169 | suit the above use case. | |
170 | ||
171 | *Availability*: | |
172 | Available in MochiKit 1.3.1+ | |
173 | ||
174 | ||
175 | :mochidef:`groupby_as_array(iterable[, keyfunc])`: | |
176 | ||
177 | Perform the same task as :mochiref:`groupby()`, except return an | |
178 | array of arrays instead of an iterator of iterators. | |
179 | ||
180 | *Availability*: | |
181 | Available in MochiKit 1.3.1+ | |
182 | ||
183 | ||
184 | :mochidef:`iextend(lst, iterable)`: | |
185 | ||
186 | Just like :mochiref:`list(iterable)`, except it pushes results on | |
187 | ``lst`` rather than creating a new one. | |
188 | ||
189 | *Availability*: | |
190 | Available in MochiKit 1.3.1+ | |
191 | ||
192 | ||
193 | :mochidef:`ifilter(pred, seq)`: | |
194 | ||
195 | ``ifilter(pred, seq)`` --> elements of seq where ``pred(elem)`` is | |
196 | ``true`` | |
197 | ||
198 | *Availability*: | |
199 | Available in MochiKit 1.3.1+ | |
200 | ||
201 | ||
202 | :mochidef:`ifilterfalse(pred, seq)`: | |
203 | ||
204 | ``ifilterfalse(pred, seq)`` --> elements of seq where | |
205 | ``pred(elem)`` is ``false`` | |
206 | ||
207 | *Availability*: | |
208 | Available in MochiKit 1.3.1+ | |
209 | ||
210 | ||
211 | :mochidef:`imap(fun, p, q[, ...])`: | |
212 | ||
213 | ``imap(fun, p, q, ...)`` --> fun(p0, q0, ...), fun(p1, q1, ...), | |
214 | ... | |
215 | ||
216 | *Availability*: | |
217 | Available in MochiKit 1.3.1+ | |
218 | ||
219 | ||
220 | :mochidef:`islice(seq, [start,] stop[, step])`: | |
221 | ||
222 | ``islice(seq, [start,] stop[, step])`` --> elements from | |
223 | seq[start:stop:step] (in Python slice syntax) | |
224 | ||
225 | *Availability*: | |
226 | Available in MochiKit 1.3.1+ | |
227 | ||
228 | ||
229 | :mochidef:`iter(iterable[, sentinel])`: | |
230 | ||
231 | Convert the given argument to an iterator (object implementing | |
232 | ``.next()``). | |
233 | ||
234 | 1. If ``iterable`` is an iterator (implements ``.next()``), then | |
235 | it will be returned as-is. | |
236 | 2. If ``iterable`` is an iterator factory (implements | |
237 | ``.iter()``), then the result of ``iterable.iter()`` will be | |
238 | returned. | |
239 | 3. If ``iterable`` is a JavaScript 1.7 iterator factory (implements | |
240 | ``.__iterable__()``), then the result of ``iterable.__iterable__()`` | |
241 | will be returned (MochiKit 1.4+). | |
242 | 4. Otherwise, the iterator factory | |
243 | :mochiref:`MochiKit.Base.AdapterRegistry` is used to find a | |
244 | match. | |
245 | 5. If no factory is found, it will throw ``TypeError`` | |
246 | ||
247 | Built-in iterator factories are present for Array-like objects, | |
248 | and objects that implement the ``iterateNext`` protocol (e.g. the | |
249 | result of Mozilla's ``document.evaluate``). | |
250 | ||
251 | When used directly, using an iterator should look like this:: | |
252 | ||
253 | var it = iter(iterable); | |
254 | try { | |
255 | while (var o = it.next()) { | |
256 | // use o | |
257 | } | |
258 | } catch (e) { | |
259 | if (e != StopIteration) { | |
260 | throw e; | |
261 | } | |
262 | // pass | |
263 | } | |
264 | ||
265 | This is ugly, so you should use the higher order functions to work | |
266 | with iterators whenever possible. | |
267 | ||
268 | *Availability*: | |
269 | Available in MochiKit 1.3.1+ | |
270 | ||
271 | ||
272 | :mochidef:`izip(p, q[, ...])`: | |
273 | ||
274 | ``izip(p, q, ...)`` --> [p0, q0, ...], [p1, q1, ...], ... | |
275 | ||
276 | *Availability*: | |
277 | Available in MochiKit 1.3.1+ | |
278 | ||
279 | ||
280 | :mochidef:`list(iterable)`: | |
281 | ||
282 | Convert ``iterable`` to a new ``Array`` | |
283 | ||
284 | *Availability*: | |
285 | Available in MochiKit 1.3.1+ | |
286 | ||
287 | ||
288 | :mochidef:`next(iterator)`: | |
289 | ||
290 | Return ``iterator.next()`` | |
291 | ||
292 | *Availability*: | |
293 | Available in MochiKit 1.3.1+ | |
294 | ||
295 | ||
296 | :mochidef:`range([start,] stop[, step])`: | |
297 | ||
298 | Return an iterator containing an arithmetic progression of integers. | |
299 | ||
300 | ``range(i, j)`` returns :mochiref:`iter([i, i + 1, i + 2, ..., j - | |
301 | 1])` | |
302 | ||
303 | ``start`` (!) defaults to ``0``. When ``step`` is given, it | |
304 | specifies the increment (or decrement). The end point is omitted! | |
305 | ||
306 | For example, ``range(4)`` returns :mochiref:`iter([0, 1, 2, 3])`. | |
307 | This iterates over exactly the valid indexes for an array of 4 | |
308 | elements. | |
309 | ||
310 | *Availability*: | |
311 | Available in MochiKit 1.3.1+ | |
312 | ||
313 | ||
314 | :mochidef:`reduce(fn, iterable[, initial])`: | |
315 | ||
316 | Apply ``fn(a, b)`` cumulatively to the items of an iterable from | |
317 | left to right, so as to reduce the iterable to a single value. | |
318 | ||
319 | For example:: | |
320 | ||
321 | reduce(function (a, b) { return x + y; }, [1, 2, 3, 4, 5]) | |
322 | ||
323 | calculates:: | |
324 | ||
325 | ((((1 + 2) + 3) + 4) + 5). | |
326 | ||
327 | If initial is given, it is placed before the items of the sequence | |
328 | in the calculation, and serves as a default when the sequence is | |
329 | empty. | |
330 | ||
331 | Note that the above example could be written more clearly as:: | |
332 | ||
333 | reduce(operator.add, [1, 2, 3, 4, 5]) | |
334 | ||
335 | Or even simpler:: | |
336 | ||
337 | sum([1, 2, 3, 4, 5]) | |
338 | ||
339 | *Availability*: | |
340 | Available in MochiKit 1.3.1+ | |
341 | ||
342 | ||
343 | :mochidef:`registerIteratorFactory(name, check, iterfactory[, override])`: | |
344 | ||
345 | Register an iterator factory for use with the iter function. | |
346 | ||
347 | ``check`` is a ``function(a)`` that returns ``true`` if ``a`` can | |
348 | be converted into an iterator with ``iterfactory``. | |
349 | ||
350 | ``iterfactory`` is a ``function(a)`` that returns an object with a | |
351 | ``.next()`` method that returns the next value in the sequence. | |
352 | ||
353 | ``iterfactory`` is guaranteed to only be called if ``check(a)`` | |
354 | returns a true value. | |
355 | ||
356 | If ``override`` is ``true``, then it will be made the | |
357 | highest precedence iterator factory. Otherwise, the lowest. | |
358 | ||
359 | *Availability*: | |
360 | Available in MochiKit 1.3.1+ | |
361 | ||
362 | ||
363 | :mochidef:`repeat(elem[, n])`: | |
364 | ||
365 | ``repeat(elem, [,n])`` --> elem, elem, elem, ... endlessly or up | |
366 | to n times | |
367 | ||
368 | *Availability*: | |
369 | Available in MochiKit 1.3.1+ | |
370 | ||
371 | ||
372 | :mochidef:`reversed(iterable)`: | |
373 | ||
374 | Return a reversed array from iterable. | |
375 | ||
376 | *Availability*: | |
377 | Available in MochiKit 1.3.1+ | |
378 | ||
379 | ||
380 | :mochidef:`some(iterable, func)`: | |
381 | ||
382 | Return ``true`` if ``func(item)`` is ``true`` for at least one | |
383 | item in ``iterable``. | |
384 | ||
385 | *Availability*: | |
386 | Available in MochiKit 1.3.1+ | |
387 | ||
388 | ||
389 | :mochidef:`sorted(iterable[, cmp])`: | |
390 | ||
391 | Return a sorted array from iterable. | |
392 | ||
393 | *Availability*: | |
394 | Available in MochiKit 1.3.1+ | |
395 | ||
396 | ||
397 | :mochidef:`sum(iterable, start=0)`: | |
398 | ||
399 | Returns the sum of a sequence of numbers plus the value of | |
400 | parameter ``start`` (with a default of 0). When the sequence is | |
401 | empty, returns start. | |
402 | ||
403 | Equivalent to:: | |
404 | ||
405 | reduce(operator.add, iterable, start); | |
406 | ||
407 | *Availability*: | |
408 | Available in MochiKit 1.3.1+ | |
409 | ||
410 | ||
411 | :mochidef:`takewhile(pred, seq)`: | |
412 | ||
413 | ``takewhile(pred, seq)`` --> seq[0], seq[1], ... until | |
414 | pred(seq[n]) fails | |
415 | ||
416 | *Availability*: | |
417 | Available in MochiKit 1.3.1+ | |
418 | ||
419 | ||
420 | :mochidef:`tee(iterable, n=2)`: | |
421 | ||
422 | ``tee(it, n=2)`` --> [it1, it2, it3, ... itn] splits one iterator | |
423 | into n | |
424 | ||
425 | *Availability*: | |
426 | Available in MochiKit 1.3.1+ | |
427 | ||
428 | ||
429 | See Also | |
430 | ======== | |
431 | ||
432 | .. [1] The iteration protocol is described in | |
433 | PEP 234 - Iterators: http://www.python.org/peps/pep-0234.html | |
434 | .. [2] Python's itertools | |
435 | module: http://docs.python.org/lib/module-itertools.html | |
436 | .. [3] Iteration in JavaScript: http://bob.pythonmac.org/archives/2005/07/06/iteration-in-javascript/ | |
437 | ||
438 | ||
439 | Authors | |
440 | ======= | |
441 | ||
442 | - Bob Ippolito <bob@redivi.com> | |
443 | ||
444 | ||
445 | Copyright | |
446 | ========= | |
447 | ||
448 | Copyright 2005 Bob Ippolito <bob@redivi.com>. This program is | |
449 | dual-licensed free software; you can redistribute it and/or modify it | |
450 | under the terms of the `MIT License`_ or the `Academic Free License | |
451 | v2.1`_. | |
452 | ||
453 | .. _`MIT License`: http://www.opensource.org/licenses/mit-license.php | |
454 | .. _`Academic Free License v2.1`: http://www.opensource.org/licenses/afl-2.1.php |