root/masterdriverz/snakeoil-formatters/snakeoil/lists.py @ masterdriverz%2540gentoo.org-20070331113622-vvn2r4825p48o15n

Revision masterdriverz%2540gentoo.org-20070331113622-vvn2r4825p48o15n, 4.0 kB (checked in by Charlie Shepherd <masterdriverz@…>, 22 months ago)

More cosmetics

Line 
1# Copyright: 2005 Brian Harring <ferringb@gmail.com>
2# License: GPL2
3
4"""
5sequence related operations
6"""
7
8from snakeoil.iterables import expandable_chain
9
10def unstable_unique(sequence):
11    """
12    lifted from python cookbook, credit: Tim Peters
13    Return a list of the elements in s in arbitrary order, sans duplicates
14    """
15
16    n = len(sequence)
17    # assume all elements are hashable, if so, it's linear
18    try:
19        return list(set(sequence))
20    except TypeError:
21        pass
22
23    # so much for linear.  abuse sort.
24    try:
25        t = sorted(sequence)
26    except TypeError:
27        pass
28    else:
29        assert n > 0
30        last = t[0]
31        lasti = i = 1
32        while i < n:
33            if t[i] != last:
34                t[lasti] = last = t[i]
35                lasti += 1
36            i += 1
37        return t[:lasti]
38
39    # blah.  back to original portage.unique_array
40    u = []
41    for x in sequence:
42        if x not in u:
43            u.append(x)
44    return u
45
46def stable_unique(iterable):
47    """
48    return unique list from iterable, preserving ordering
49    """
50    return list(iter_stable_unique(iterable))
51
52def iter_stable_unique(iterable):
53    """
54    generator yielding unique elements from iterable, preserving ordering
55    """
56    s = set()
57    for x in iterable:
58        if x not in s:
59            yield x
60            s.add(x)
61
62def native_iflatten_instance(l, skip_flattening=(basestring,)):
63    """
64    collapse [[1],2] into [1,2]
65
66    @param skip_flattening: list of classes to not descend through
67    """
68    if isinstance(l, skip_flattening):
69        yield l
70        return
71    iters = expandable_chain(l)
72    try:
73        while True:
74            x = iters.next()
75            if hasattr(x, '__iter__') and not isinstance(x, skip_flattening):
76                iters.appendleft(x)
77            else:
78                yield x
79    except StopIteration:
80        pass
81
82def native_iflatten_func(l, skip_func):
83    """
84    collapse [[1],2] into [1,2]
85
86    @param skip_func: a callable that returns True when iflatten_func should
87        descend no further
88    """
89    if skip_func(l):
90        yield l
91        return
92    iters = expandable_chain(l)
93    try:
94        while True:
95            x = iters.next()
96            if hasattr(x, '__iter__') and not skip_func(x):
97                iters.appendleft(x)
98            else:
99                yield x
100    except StopIteration:
101        pass
102
103
104try:
105    # No name "readdir" in module osutils
106    # pylint: disable-msg=E0611
107    from snakeoil._lists import iflatten_instance, iflatten_func
108    cpy_builtin = True
109except ImportError:
110    cpy_builtin = False
111    cpy_iflatten_instance = cpy_iflatten_func = None
112    iflatten_instance = native_iflatten_instance
113    iflatten_func = native_iflatten_func
114
115
116class ChainedLists(object):
117    """
118    sequences chained together, without collapsing into a list
119    """
120    __slots__ = ("_lists", "__weakref__")
121
122    def __init__(self, *lists):
123        """
124        all args must be sequences
125        """
126        # ensure they're iterable
127        for x in lists:
128            iter(x)
129
130        if isinstance(lists, tuple):
131            lists = list(lists)
132        self._lists = lists
133
134    def __len__(self):
135        return sum(len(l) for l in self._lists)
136
137    def __getitem__(self, idx):
138        if idx < 0:
139            idx += len(self)
140            if idx < 0:
141                raise IndexError
142        for l in self._lists:
143            l2 = len(l)
144            if idx < l2:
145                return l[idx]
146            idx -= l2
147        else:
148            raise IndexError
149
150    def __setitem__(self, idx, val):
151        raise TypeError("not mutable")
152
153    def __delitem__(self, idx):
154        raise TypeError("not mutable")
155
156    def __iter__(self):
157        for l in self._lists:
158            for x in l:
159                yield x
160
161    def __contains__(self, obj):
162        return obj in iter(self)
163
164    def __str__(self):
165        return "[ %s ]" % ", ".join(str(l) for l in self._lists)
166
167    def append(self, item):
168        self._lists.append(item)
169
170    def extend(self, items):
171        self._lists.extend(items)
Note: See TracBrowser for help on using the browser.