Combine a list into tuple pairs (x, y)

8.1k views Asked by At

I'm trying to combine pairs of numbers passed in via sys.argv. Example:

python myscript.py -35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980

My goal would be to turn these into sets of two's in tuples. Like such:

((-35.12323,112.76767),(-36.33345,112.76890),(-33.68689,111.8980))

This is what I've tried to so far, but it has a problem when I pass the results to the Shapely Point and Polygon methods.

from shapely.geometry import Polygon
from shapely.geometry import Point
import sys

def args_to_tuple(list):
    arglist = []

    for coord in list:
        arglist.append(float(coord))

    i = 0
    polylist = []

    for xory in arglist:
        tmp = (arglist[i],arglist[i+1])
        polylist.append(tmp)

    return tuple(polylist)


poly = Polygon(args_to_tuple(sys.argv[3:]))

# xy pair for point is first two sys args
point = Point(args_to_tuple(sys.argv[1:3]))

print point.within(poly) # should result in true, but doesn't
print poly.contains(point) # should result in true, but doesn't

It seems like this would be something common in itertools, but I can't seem to find anything in that module that lets you grab items in a pair.

5

There are 5 answers

4
TigerhawkT3 On
def args_to_tuple(lst):
    it = iter(map(float, lst.split()))
    return [(item, next(it)) for item in it]

>>> a = '-35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980'
>>> args_to_tuple(a)
[(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]
4
Konstantin On
In [10]: args_str = '-35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980'

In [11]: args = map(float, args_str.split())

In [12]: args
Out[12]: [-35.12323, 112.76767, -36.33345, 112.7689, -33.68689, 111.898]

In [13]: zip(args[::2], args[1::2])
Out[13]: [(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]

zip can be replaced with itertools.izip which produces an iterator instead of a list.

6
parity3 On

I would guess the Point constructor would probably take 1 pair, not a tuple containing 1 pair? To do this, you'd need to change:

point = Point(args_to_tuple(sys.argv[1:3]))

To:

point = Point(args_to_tuple(sys.argv[1:3])[0])

Or maybe:

point = Point(*args_to_tuple(sys.argv[1:3])[0])

Without knowing the shapely API I'm not sure.

As for converting arguments to a tuple of pairs, your method does just fine. However, if you want a pre-packaged no-hassle solution, I'd look at pytoolz's partition_all method for grouping pairs together. Also look at cytoolz, which strives to make those methods comparable to C in performance.

EDIT

I noticed a bug in your method. You are not incrementing i in your loop from your args_to_tuple method! Here is a revised version where you populate polylist:

polylist = [(arglist[i],arglist[i+1]) for i in xrange(0,len(arglist),2)]
1
dting On
args_list = "-35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980".split()

You can zip the same iterator object to get pairs that you want:

a = (float(x) for x in args_list)
zip(a, a)
# [(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]

For each tuple that zip returns next is called on the same iterator object twice, pairing up your arguments in the desired fashion.

For python 3 you can just use a map since map returns an iterable map object instead of a generator expression.

%%python3

a = map(float, args_list)
print(tuple(zip(a, a)))
# ((-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898))

You can also wrap the list returned by map using the iter built-in for python 2.

%%python2

a = iter(map(float, args_list)
print zip(a, a)
# [(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]
0
Kenny Powers On

Thanks guys for pointing me in the right direction! Here's my solution for future reference. Not sure why my crappier method wasn't working, but this seems pythonic and simple enough to go with.

from shapely.geometry import Polygon
from shapely.geometry import Point
import sys

#point = Point(38.27269, -120.98145)

# Point
l = map(float, sys.argv[1:3])
point = Point(tuple((l[0],l[1])))


# Polygon
l = map(float, sys.argv[3:])
poly = Polygon(tuple(zip(l[::2], l[1::2])))

# Test
print point.within(poly) # should result in true
print poly.contains(point) # should result in true