0

I have a list structured like so:

>>> print(pts)
[[(120, 1200), (121, 1201), (122, 1202)],
 [(130, 1300), (131, 1301), (132, 1302)]]

And I need all the x and y points concatenated seperately like so:

>>> print(y)
[120 121 122 130 131 132]
>>> print(x)
[1200 1201 1202 1300 1301 1302

The original list is created by the following method:

pts = []
y = [120, 121, 122]
x = [1200, 1201, 1202]
pts.append(list(zip(y, x)))
x = [1300, 1301, 1302]
y = [130, 131, 132]
pts.append(list(zip(y, x)))

The final result must be seperate y and x lists so I can use it with np.polyfit(). The length of both the individual points list and overal list will vary, however, I will always have equal length of y and x points. I'm thinking there should be a way to reshape and slice? Maybe I could flatten and take all the even indices for x and odd indices for y?

DrTarr
  • 922
  • 2
  • 15
  • 34

3 Answers3

4

You can try this:

from itertools import chain

pts = [[(120, 1200), (121, 1201), (122, 1202)],
[(130, 1300), (131, 1301), (132, 1302)]]

all_points = list(chain(*pts))

y = [i[0] for i in all_points]

x = [i[1] for i in all_points]

print y

print x

Output:

[120, 121, 122, 130, 131, 132]

[1200, 1201, 1202, 1300, 1301, 1302]

itertools.chain() will allow you to flatten the nested list and be able to access the tuples.

Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • You're the winner, thanks! Although to flatten the list I used all_points = [item for sublist in pts for item in sublist]. Real issue was I didn't know how to pull out the indices of the array into a new list. Thanks! – DrTarr Jul 10 '17 at 14:12
  • @NateGreco Consider accepting this answer if it helped you, it helps the community. – cs95 Jul 10 '17 at 14:13
  • I did, there's a 5 minute limit. – DrTarr Jul 10 '17 at 14:15
3

You can also use zip with list comprehension:

x, y = zip(*(p for s in pts for p in s))

x
# (120, 121, 122, 130, 131, 132)

y
# (1200, 1201, 1202, 1300, 1301, 1302)
Psidom
  • 209,562
  • 33
  • 339
  • 356
  • 1
    Posted before I realised we had the same thing. +1. By the way, might want to apply one last `map(list, ...)` to return a list of points. – cs95 Jul 10 '17 at 14:07
  • @cᴏʟᴅsᴘᴇᴇᴅ Thanks for the comment. I think `np.polyfit` also accepts tuples as argument, so it shouldn't matter that much in this case. But it will be something nice to have to achieve what OP has in mind. – Psidom Jul 10 '17 at 14:10
  • `polyfit` applies `asarray` to the 2 inputs. – hpaulj Jul 10 '17 at 16:09
1

Normally a pure list approach is faster when starting with small lists. But since you are feeding a numpy function, which probably will apply asarray to its inputs, I'd suggest an array transpose approach.

arr = np.array(pts) # 2x3x2 array
arr = arr.reshape(6,2)
x, y = arr.T   # unpack a 2x6 array

Testing:

In [614]: pts
Out[614]: 
[[(120, 1200), (121, 1201), (122, 1202)],
 [(130, 1300), (131, 1301), (132, 1302)]]
In [615]: np.array(pts).shape
Out[615]: (2, 3, 2)
In [616]: np.array(pts).reshape(-1,2).T
Out[616]: 
array([[ 120,  121,  122,  130,  131,  132],
       [1200, 1201, 1202, 1300, 1301, 1302]])
In [617]: y, x = np.array(pts).reshape(-1,2).T
In [618]: y
Out[618]: array([120, 121, 122, 130, 131, 132])
In [619]: x
Out[619]: array([1200, 1201, 1202, 1300, 1301, 1302])

np.polyfit starts with:

order = int(deg) + 1
x = NX.asarray(x) + 0.0
y = NX.asarray(y) + 0.0

If pts had been created with extend the common zip* would have been enough

In [625]: pts = []
     ...: y = [120, 121, 122]
     ...: x = [1200, 1201, 1202]
     ...: pts.extend(list(zip(y, x)))
     ...: x = [1300, 1301, 1302]
     ...: y = [130, 131, 132]
     ...: pts.extend(list(zip(y, x)))
     ...: 
In [626]: pts
Out[626]: [(120, 1200), (121, 1201), (122, 1202), (130, 1300), (131, 1301), (132, 1302)]
In [627]: y,x = list(zip(*pts))
In [628]: y
Out[628]: (120, 121, 122, 130, 131, 132)
In [629]: x
Out[629]: (1200, 1201, 1202, 1300, 1301, 1302)

The chain flattening can be combined with the *zip transpose, eliminating the need for any list comprehension.

In [642]: pts
Out[642]: 
[[(120, 1200), (121, 1201), (122, 1202)],
 [(130, 1300), (131, 1301), (132, 1302)]]
In [643]: y,x=list(zip(*chain(*pts)))
In [644]: y
Out[644]: (120, 121, 122, 130, 131, 132)
In [645]: x
Out[645]: (1200, 1201, 1202, 1300, 1301, 1302)
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • extend would have been a good choice, however, I also must maintain the ability to delete indices (a set of points) later on. – DrTarr Jul 10 '17 at 16:21