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