当前位置: 动力学知识库 > 问答 > 编程问答 >

python - Unravel list into sublist in nested list

问题描述:

I have a list l in the following way:

l = [([1, 0.0, 50.0, 2, 0.0, 50.0], [1, 1.9, 1]),

([1, 0.0, 50.0, 2, 0.0, 50.0], [2, 1.9, 1])]

I want to transform this list such that the new structure is as follows:

goal = [([1, 0.0, 50.0], [2, 0.0, 50.0], [1, 1.9, 1]), ([1, 0.0, 50.0], [2, 0.0, 50.0], [2, 1.9, 1])]

Namely, that the first list in each tuple gets unraveled to sublists of length 3.

I tried it the following way but got stuck as the various transformations give back numpy arrays and it turns out messy.

Additionally, this operation could potentially take place on large variants of l so should be performance friendly/in-place(?).

terms = np.array(l)[:,0]

[np.split(np.array(i), 2) for i in terms]

网友答案:

In my comment I argued against the use of np.array for this, since

In [241]: np.array(l)
Out[241]: 
array([[[1, 0.0, 50.0, 2, 0.0, 50.0], [1, 1.9, 1]],
       [[1, 0.0, 50.0, 2, 0.0, 50.0], [2, 1.9, 1]]], dtype=object)

is an object array. However the array version can make splitting a list easy, with reshape

In [240]: [np.array(x[0]+x[1]).reshape(-1,3).tolist() for x in l]
Out[240]: 
[[[1.0, 0.0, 50.0], [2.0, 0.0, 50.0], [1.0, 1.9, 1.0]],
 [[1.0, 0.0, 50.0], [2.0, 0.0, 50.0], [2.0, 1.9, 1.0]]]

Add [tuple(n... if it must be tuples, not lists.

I'm doing a couple of tricks. Since the second item has the same length as the desired split (3), I'm just concatenating them at the start, rather worry about doing so later. And then array reshape followed by tolist effectively splits the array.

In [246]: np.reshape(x[0]+x[1],(-1,3))
Out[246]: 
array([[  1. ,   0. ,  50. ],
       [  2. ,   0. ,  50. ],
       [  1. ,   1.9,   1. ]])

This depends on being able to split the sublists evenly by 3.

The array round trip is probably slower than the equivalent itertools code.


in-place won't work because you have a list of tuples. You can replace those tuples, but you can't modify them. If they were lists, you could splice in the split like this:

In [248]: x
Out[248]: ([1, 0.0, 50.0, 2, 0.0, 50.0], [1, 1.9, 1])
In [249]: xl=list(x)

In [250]: xl[0:1] = [xl[0][:3],xl[0][3:]]   # or the split of your choice
In [251]: xl
Out[251]: [[1, 0.0, 50.0], [2, 0.0, 50.0], [1, 1.9, 1]]

Often it is more convenient to create new lists and tuples than to change things in place. Copying a list of lists just means making a new list of the same pointers.


Since it is ok to slice off the end of a list @Kasramvd's islice version can be simplified to:

[tuple([i[t:t+3]  for i in sub for t in range(0, len(i), 3)]) for sub in l]
网友答案:

You can use itertools.chain within a list comprehension:

In [23]: from itertools import chain

In [24]: [tuple(chain.from_iterable((i[:3], i[3:]) if len(i) > 3 else [i] for i in sub)) for sub in l]
Out[24]: 
[([1, 0.0, 50.0], [2, 0.0, 50.0], [1, 1.9, 1]),
 ([1, 0.0, 50.0], [2, 0.0, 50.0], [2, 1.9, 1])]

As a general way you can use itertools.islice in order to slice your sub lists to triples:

In [37]: [tuple(list(islice(i,t,t+3)) if len(i) > 3 else i for i in sub for t in range(0, len(i), 3)) for sub in l]
Out[37]: 
[([1, 0.0, 50.0], [2, 0.0, 50.0], [1, 1.9, 1]),
 ([1, 0.0, 50.0], [2, 0.0, 50.0], [2, 1.9, 1])]
分享给朋友:
您可能感兴趣的文章:
随机阅读: