0
\$\begingroup\$

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?

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to codereview! As it is, your question is off-topic because the code is broken. Didn't you mean latlon instead of coords ? \$\endgroup\$ – Grajdeanu Alex. Nov 7 '16 at 16:28
  • \$\begingroup\$ More, what version of Python would you like to be used when somebody will review your question ? \$\endgroup\$ – Grajdeanu Alex. Nov 7 '16 at 16:32
  • \$\begingroup\$ @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):. \$\endgroup\$ – 409_Conflict Nov 7 '16 at 16:54
3
\$\begingroup\$

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)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.