|
18 | 18 | # http://www.gnu.org/licenses/
|
19 | 19 | #*****************************************************************************
|
20 | 20 |
|
21 |
| -from sage.misc.all import cached_function |
| 21 | +from collections import Iterable, Sequence |
| 22 | +from sage.misc.cachefunc import cached_function |
| 23 | +from sage.structure.parent import Parent |
| 24 | +from sage.categories.enumerated_sets import EnumeratedSets |
22 | 25 |
|
23 | 26 | def from_list(l):
|
24 | 27 | """
|
@@ -134,3 +137,113 @@ def unrank(i):
|
134 | 137 | return None
|
135 | 138 |
|
136 | 139 | return [rank, unrank]
|
| 140 | + |
| 141 | +def unrank(L, i): |
| 142 | + r""" |
| 143 | + Return the `i`-th element of `L`. |
| 144 | +
|
| 145 | + INPUT: |
| 146 | +
|
| 147 | + - ``L`` -- a list, tuple, finite enumerated set, ... |
| 148 | + - ``i`` -- an int or :class:`Integer` |
| 149 | +
|
| 150 | + The purpose of this utility is to give a uniform idiom to recover |
| 151 | + the `i`-th element of an object ``L``, whether ``L`` is a list, |
| 152 | + tuple (or more generally a :class:`collections.Sequence`), an |
| 153 | + enumerated set, some old parent of Sage still implementing |
| 154 | + unranking in the method ``__getitem__``, or an iterable (see |
| 155 | + :class:`collections.Iterable`). See :trac:`15919`. |
| 156 | +
|
| 157 | + EXAMPLES: |
| 158 | +
|
| 159 | + Lists, tuples, and other :class:`sequences <collections.Sequence>`:: |
| 160 | +
|
| 161 | + sage: from sage.combinat.ranker import unrank |
| 162 | + sage: unrank(['a','b','c'], 2) |
| 163 | + 'c' |
| 164 | + sage: unrank(('a','b','c'), 1) |
| 165 | + 'b' |
| 166 | + sage: unrank(xrange(3,13,2), 1) |
| 167 | + 5 |
| 168 | +
|
| 169 | + Enumerated sets:: |
| 170 | +
|
| 171 | + sage: unrank(GF(7), 2) |
| 172 | + 2 |
| 173 | + sage: unrank(IntegerModRing(29), 10) |
| 174 | + 10 |
| 175 | +
|
| 176 | + An old parent with unranking implemented in ``__getitem__``:: |
| 177 | +
|
| 178 | + sage: M = MatrixSpace(GF(3), 2, 2) |
| 179 | + sage: hasattr(M, "unrank") |
| 180 | + False |
| 181 | + sage: M[42] |
| 182 | + [1 0] |
| 183 | + [2 1] |
| 184 | + sage: unrank(M, 42) |
| 185 | + [1 0] |
| 186 | + [2 1] |
| 187 | +
|
| 188 | + An iterable:: |
| 189 | +
|
| 190 | + sage: unrank(NN,4) |
| 191 | + 4 |
| 192 | +
|
| 193 | + An iterator:: |
| 194 | +
|
| 195 | + sage: unrank(('a{}'.format(i) for i in range(20)), 0) |
| 196 | + 'a0' |
| 197 | + sage: unrank(('a{}'.format(i) for i in range(20)), 2) |
| 198 | + 'a2' |
| 199 | +
|
| 200 | + .. WARNING:: |
| 201 | +
|
| 202 | + When unranking an iterator, it returns the``i``-th element |
| 203 | + beyond where it is currently at:: |
| 204 | +
|
| 205 | + sage: from sage.combinat.ranker import unrank |
| 206 | + sage: it = iter(range(20)) |
| 207 | + sage: unrank(it, 2) |
| 208 | + 2 |
| 209 | + sage: unrank(it, 2) |
| 210 | + 5 |
| 211 | +
|
| 212 | + TESTS:: |
| 213 | +
|
| 214 | + sage: from sage.combinat.ranker import unrank |
| 215 | + sage: unrank(range(3), 10) |
| 216 | + Traceback (most recent call last): |
| 217 | + ... |
| 218 | + IndexError: list index out of range |
| 219 | +
|
| 220 | + sage: unrank(('a{}'.format(i) for i in range(20)), 22) |
| 221 | + Traceback (most recent call last): |
| 222 | + ... |
| 223 | + IndexError: index out of range |
| 224 | +
|
| 225 | + sage: M[100] |
| 226 | + Traceback (most recent call last): |
| 227 | + ... |
| 228 | + IndexError: list index out of range |
| 229 | + """ |
| 230 | + if L in EnumeratedSets: |
| 231 | + return L.unrank(i) |
| 232 | + if isinstance(L, Sequence): |
| 233 | + return L[i] |
| 234 | + if isinstance(L, Parent): |
| 235 | + # handle parents still implementing unranking in __getitem__ |
| 236 | + try: |
| 237 | + return L[i] |
| 238 | + except (AttributeError, TypeError, ValueError): |
| 239 | + pass |
| 240 | + if isinstance(L, Iterable): |
| 241 | + try: |
| 242 | + it = iter(L) |
| 243 | + for _ in range(i): |
| 244 | + it.next() |
| 245 | + return it.next() |
| 246 | + except StopIteration as e: |
| 247 | + raise IndexError("index out of range") |
| 248 | + raise ValueError("Don't know how to unrank on {}".format(L)) |
| 249 | + |
0 commit comments