I'm not sure about the definition of pythonic but you can do the following (in increasing order of complexity).
TLDR: Take method 3.
For comparison, I also list the maximum memory footprints (M) using Gnu time as well as the computation times (T) using the jupyters built-in function %timeit -n 4 -r 4
.
The reference size
/usr/bin/time -v python3 -c 'list( int(1e6) * "abcdef" )'
results in 61.4 MB.
Method 1
As suggested earlier:
reversed( list( enumerate(l) ) )
enumerate
returns a generator, and generators are not invertible.
So list
internally creates a new list by iterating over the entire generator (until a StopIteration
exception is thrown) and reversed
creates a generator along that list in reverse order.
This is simple and probably "pythonic", but creates significant memory overhead (during copying and due to the copying itself).
M |
T (ms per loop [mean ± std. dev. of 4 runs, 4 loops each]) |
673.6 MB |
1.03 s ± 61.3 ms |
Method 2
As written in my comment, you can also use
sorted( enumerate(), reverse=True )
which is slighly more clear as the above and does pretty much the same.
sorted
also internally create a copy with the associated memory-overhead but additionally a sorting operation.
As sorting a sorted list is rather fast, the run-time overhead is tiny.
So you are trading readability for runtime here.
M |
T (ms per loop [mean ± std. dev. of 4 runs, 4 loops each]) |
673.6 MB |
1.28 s ± 30.2 ms |
Method 3
For what you ask, as far as I know, there is no built-in generator or way to chain generators. But you can easily write one yourself, and that is what I recommend:
def enumerate_reversed(l):
return zip(range(len(l)-1, -1, -1), reversed(l))
Or as one-liner:
enumerate_reversed = lambda l: zip(range(len(l)-1, -1, -1), reversed(l))
reversed
, range
and zip
all return generators.
This way you get an inverted enumerate
without creating any intermediate copies.
M |
T (ms per loop [mean ± std. dev. of 4 runs, 4 loops each]) |
T (lambda) |
61.8 MB |
1.04 s ± 26.7 ms |
1.04 s ± 30.6 ms per loop |
Appendix:
Commands used:
Method |
Command |
1 |
/usr/bin/time -f "%M" python3 -c 'reversed(list(enumerate(list(int(1e6)*"abcdef"))))' |
2 |
/usr/bin/time -f "%M" python3 -c 'sorted(enumerate(list(int(1e6)*"abcdef")),reverse=True)' |
3 |
/usr/bin/time -f "%M" python3 -c 'f = lambda l: zip(range(len(l)-1, -1, -1), reversed(l)); f(list(int(1e6)*"abcdef"))' |
len(string) - i
and get the value you're looking for. – Chancellorlist(enumerate(s))[::-1]
– Knowreversed(list(enumerate(array)))
- You have to convert the generator to a list before reversing it. – Excisesorted( enumerate( l, reverse=True ) )
– Dairen