|
1 """ |
|
2 Providing iterator functions that are not in all version of Python we support. |
|
3 Where possible, we try to use the system-native version and only fall back to |
|
4 these implementations if necessary. |
|
5 """ |
|
6 |
|
7 import itertools |
|
8 |
|
9 def compat_tee(iterable): |
|
10 """ |
|
11 Return two independent iterators from a single iterable. |
|
12 |
|
13 Based on http://www.python.org/doc/2.3.5/lib/itertools-example.html |
|
14 """ |
|
15 # Note: Using a dictionary and a list as the default arguments here is |
|
16 # deliberate and safe in this instance. |
|
17 def gen(next, data={}, cnt=[0]): |
|
18 dpop = data.pop |
|
19 for i in itertools.count(): |
|
20 if i == cnt[0]: |
|
21 item = data[i] = next() |
|
22 cnt[0] += 1 |
|
23 else: |
|
24 item = dpop(i) |
|
25 yield item |
|
26 next = iter(iterable).next |
|
27 return gen(next), gen(next) |
|
28 |
|
29 def groupby(iterable, keyfunc=None): |
|
30 """ |
|
31 Taken from http://docs.python.org/lib/itertools-functions.html |
|
32 """ |
|
33 if keyfunc is None: |
|
34 keyfunc = lambda x:x |
|
35 iterable = iter(iterable) |
|
36 l = [iterable.next()] |
|
37 lastkey = keyfunc(l[0]) |
|
38 for item in iterable: |
|
39 key = keyfunc(item) |
|
40 if key != lastkey: |
|
41 yield lastkey, l |
|
42 lastkey = key |
|
43 l = [item] |
|
44 else: |
|
45 l.append(item) |
|
46 yield lastkey, l |
|
47 |
|
48 # Not really in itertools, since it's a builtin in Python 2.4 and later, but it |
|
49 # does operate as an iterator. |
|
50 def reversed(data): |
|
51 for index in xrange(len(data)-1, -1, -1): |
|
52 yield data[index] |
|
53 |
|
54 if hasattr(itertools, 'tee'): |
|
55 tee = itertools.tee |
|
56 else: |
|
57 tee = compat_tee |
|
58 if hasattr(itertools, 'groupby'): |
|
59 groupby = itertools.groupby |
|
60 |
|
61 def is_iterable(x): |
|
62 "A implementation independent way of checking for iterables" |
|
63 try: |
|
64 iter(x) |
|
65 except TypeError: |
|
66 return False |
|
67 else: |
|
68 return True |
|
69 |