# Generate lines from points in Python

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?

• Welcome to codereview! As it is, your question is off-topic because the code is broken. Didn't you mean latlon instead of coords ? – Grajdeanu Alex. Nov 7 '16 at 16:28
• More, what version of Python would you like to be used when somebody will review your question ? – Grajdeanu Alex. Nov 7 '16 at 16:32
• @Dex'ter There is nothing that requires the two snippets to be that related. For what it's worth, latlon could be passed to a function defined along the lines of def whatever(coords):. – 301_Moved_Permanently Nov 7 '16 at 16:54

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)