Here is the case:
mylist = range(100)
and I have a discontinuous path from src=1
to dest=99
with an array pre[100]
, each value of which represents the last elem
in the path
.
The question is: How can I get all the elems
in the path
from dest
to src
. Can do like this:
path = []
i = dst
while i != src:
path.append(i)
i = pre[i]
path.append(src)
But, is there any simpler way maybe using just only one statement?
Sample Input
dst, src = 3, 2
pre = [2, 0, 3, 1]
Output
[3, 1, 0, 2] #It just have to follow the path with the indices from 3 to 2.
Explanation:
src dst v v Indices: 0 1 2 3 Pre : 2 0 3 1 From dest 3, the predecessor is 1, so we go to 1. From node 1, the predecessor is 0, so we go to 0. From node 0, the predecessor is 2, so we go to 2. 2 is src, so we're done.
The Pythonic way is to either use your existing loop, or to use an equivalent generator function:
def gen_path(src, dst, pre):
while dst != src:
yield dst
dst = pre[dst]
yield src
Then to get a list, you'd call it with list(gen_path(src, dst, pre))
.
There is no way to do this in a single basic expression, because there is state involved (what node in the path you're on). It probably is possible using complicated, hackish stuff like 2-argument next
and lambda
s with default arguments, but you don't want to go there.
NOTE: I am not recommending this. In real code I would write the loop. The loop is simple and clear. The loop is already pythonic. Maybe use yield
instead of materializing a list, but that's easy.
As I put it once: "What seems unpythonic to me is spending time worrying about making perfectly clear code more pythonic. The Pythonicness which needs hours of thought is not the true Pythonicness."
But for entertainment purposes, and because the Colts just won, a one-liner:
>>> from itertools import takewhile, accumulate, repeat
>>> dst, src = 3, 2
>>> pre = [2, 0, 3, 1]
>>> list(takewhile(lambda x: x != src,
accumulate(repeat(dst), lambda x,y: pre[x]))) + [src]
[3, 1, 0, 2]
This will only work in Python >= 3.3, in which accumulate
accepts a binary-argument function as its second argument. This comes in useful in cases where you want a reduce
which gives the partial results, and reminding everyone about this new functionality is about the only excuse I have for this answer..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With