app/django/utils/itercompat.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     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