I have two lists of coordinates,
lat = [-23.23, -44.23, -12.23]
lon = [-21.23, -14.23, -62.23]
and I generate a tuple of lat long
pairs with zip
:
latlon = zip(lat, lon)
and that gives the expected result. Now there is a very common pattern of generating lines with the points. It is common to do something like
line_coords = []
for i in xrange(len(coords)-1):
line_coords.append([tuple(coords[i]), tuple(coords[i+1])])
so the result is now a list of tuples, each tuple an list of beginning and end of a line:
line_coords
[[(-23.23, -21.23), (-44.23, -14.23)], [(-44.23, -14.23), (-12.23, -62.23)] ]
and it get worse if the line needs to come back to the beginning. This looks like an anti-pattern. Is there a name for this pattern and a more elegant way to do it?
1 Answer 1
When it comes to iteration in Python, there is often an itertools
recipe or function that come close to the needs.
Here, I’m thinking about pairwise
which is defined as:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return itertools.izip(a, b)
If you’re interested in cycling back to the beginnig, you should consider itertools.cycle
too:
def get_line_coordinates(iterable, close=False):
"""s -> (s0,s1), (s1,s2), (s2, s3), ...
ends with (sN, s0) if close is True else (sN-1, sN)
"""
a, b = itertools.tee(iterable)
if close:
b = itertools.cycle(b)
next(b, None)
return itertools.izip(a, b)
Lastly, itertools.izip_longest
will let you fill that last value by consumming less memory than cycle
:
def get_line_coordinates(iterable, close=False):
"""s -> (s0,s1), (s1,s2), (s2, s3), ...
ends with (sN, s0) if close is True else (sN-1, sN)
"""
a, b = itertools.tee(iterable)
beginning = next(b, None)
if close:
return itertools.izip_longest(a, b, fillvalue=beginning)
return itertools.izip(a, b)
latlon
instead ofcoords
? \$\endgroup\$latlon
could be passed to a function defined along the lines ofdef whatever(coords):
. \$\endgroup\$