Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how to separate a list into two lists?

188 views
Skip to first unread message

smith jack

unread,
Aug 6, 2011, 1:07:00 PM8/6/11
to pytho...@python.org
if a list L is composed with tuple consists of two elements, that is
L = [(a1, b1), (a2, b2) ... (an, bn)]

is there any simple way to divide this list into two separate lists , such that
L1 = [a1, a2... an]
L2=[b1,b2 ... bn]

i do not want to use loop, any methods to make this done?

Chris Angelico

unread,
Aug 6, 2011, 1:14:16 PM8/6/11
to pytho...@python.org

One easy way is to use list comprehensions. Technically that'll
involve a loop, but the loop is handled efficiently under the hood.

L1 = [x[0] for x in L]
L2 = [x[1] for x in L]

Another way would be to construct a dictionary from your list of
tuples and then use the keys() and values() of that dictionary to form
your lists (use collections.OrderedDict if the order matters). But I
think the list comps are the best way.

ChrisA

Emile van Sebille

unread,
Aug 6, 2011, 1:24:10 PM8/6/11
to pytho...@python.org
On 8/6/2011 10:07 AM smith jack said...

> if a list L is composed with tuple consists of two elements, that is
> L = [(a1, b1), (a2, b2) ... (an, bn)]
>
> is there any simple way to divide this list into two separate lists , such that
> L1 = [a1, a2... an]
> L2=[b1,b2 ... bn]
>

>>> L = [('a1', 'b1'), ('a2', 'b2'),('an', 'bn')]
>>> zip(*L)
[('a1', 'a2', 'an'), ('b1', 'b2', 'bn')]


Emile


Zero Piraeus

unread,
Aug 6, 2011, 1:30:49 PM8/6/11
to pytho...@python.org
:

> if a list L is composed with tuple consists of two elements, that is
> L = [(a1, b1), (a2, b2) ... (an, bn)]
>
> is there any simple way to divide this list into two separate lists , such that
> L1 = [a1, a2... an]
> L2=[b1,b2 ... bn]

How about this?

>>> L = [("a1", "b1"), ("a2", "b2"), ("an", "bn")]
>>> L1, L2 = zip(*L)
>>> L1


('a1', 'a2', 'an')

>>> L2


('b1', 'b2', 'bn')

http://docs.python.org/library/functions.html#zip

 -[]z.

bud

unread,
Aug 6, 2011, 2:13:20 PM8/6/11
to


(x,y) = [ [z[i] for z in L] for i in range(len(L[0]))]

x
: ['a1', 'a2', 'an']

y
: ['b1', 'b2', 'bn']


bud

unread,
Aug 6, 2011, 2:21:40 PM8/6/11
to

Nice. :) I forgot about zip, still learning Python myself.

I'll have to check up on the *L - is that a reference?
I know in Perl, you can assign the lhs to a list,
below works because there are exactly 2 items on the rhs.
Does Python have a catchall, or an ignore the rest?
Example, if L was a tuple that had 3 or more items,
the below lhs would fail. Is this possible in Python?


(X,Y) = zip(*L)


X
: ('a1', 'a2', 'an')

Y
: ('b1', 'b2', 'bn')

Chris Angelico

unread,
Aug 6, 2011, 2:35:53 PM8/6/11
to pytho...@python.org
On Sat, Aug 6, 2011 at 7:21 PM, bud <on...@fleshwound.org> wrote:
> Nice. :)  I forgot about zip, still learning Python myself.
>
> I'll have to check up on the *L - is that a reference?
> I

It expands the list into the arguments. It's the parallel to:

def func(*args):

which collapses the args into a list.

ChrisA

Gelonida N

unread,
Aug 6, 2011, 4:00:46 PM8/6/11
to pytho...@python.org
Asuming you are not an alias of Jack Smith and assuming you did not see
Jack's thread asking the same question:

x,y = unzip(*L)

David Robinow

unread,
Aug 6, 2011, 4:53:42 PM8/6/11
to pytho...@python.org
On Sat, Aug 6, 2011 at 1:23 PM, Kabie <kabi...@gmail.com> wrote:
> No.
> L1, L2 = zip(*L)

Not quite. That makes L1 & L2 tuples.

L1, L2 = zip(*L)
L1 = list(L1)
L2 = list(L2)
???

Steven D'Aprano

unread,
Aug 6, 2011, 8:07:23 PM8/6/11
to
Gelonida N wrote:

> Asuming you [Bud] are not an alias of Jack Smith and assuming you did

> not see Jack's thread asking the same question:

That's a strange thing to say when Bud *answered* Jack's question.

> x,y = unzip(*L)

What's unzip? It doesn't exist in any version of Python between 1.5 and 3.3
that I have.

--
Steven

Steven D'Aprano

unread,
Aug 6, 2011, 8:13:02 PM8/6/11
to
bud wrote:

> I'll have to check up on the *L - is that a reference?

No, as Chris already answered, unary * is used for packing and unpacking
positional arguments to functions; unary ** is similarly used for
collecting keyword arguments.


> I know in Perl, you can assign the lhs to a list,
> below works because there are exactly 2 items on the rhs.
> Does Python have a catchall, or an ignore the rest?

Yes. In Python 3, you can do this:

>>> a, b, *t, c = (1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> t
[3, 4, 5, 6, 7, 8]

(but not in Python 2)


--
Steven

Steven D'Aprano

unread,
Aug 6, 2011, 8:27:24 PM8/6/11
to
Chris Angelico wrote:

> On Sat, Aug 6, 2011 at 6:07 PM, smith jack <thin...@gmail.com> wrote:
>> if a list L is composed with tuple consists of two elements, that is
>> L = [(a1, b1), (a2, b2) ... (an, bn)]
>>
>> is there any simple way to divide this list into two separate lists ,
>> such that L1 = [a1, a2... an]
>> L2=[b1,b2 ... bn]
>>
>> i do not want to use loop, any methods to make this done?
>
> One easy way is to use list comprehensions. Technically that'll
> involve a loop, but the loop is handled efficiently under the hood.
>
> L1 = [x[0] for x in L]
> L2 = [x[1] for x in L]

I hardly think that's "under the hood". It's right there: for x in L. How
much more explicitly a loop do you want?

To the original poster, Jack: if you don't loop over the list, how do you
expect to operate on each and every item?

Whether you write:

L1, L2 = [], []
for a,b in L:
L1.append(a)
L2.append(b)

or

L1, L2 = zip(*L)

or

L1 = [x[0] for x in L]
L2 = [x[1] for x in L]

you are still looping over the list. In the second case, the one-liner using
zip, you loop *twice*: once to unpack L into separate arguments, the second
time to zip them up. And the result you end up with are tuples, not lists,
so if you need lists, you have to loop *again*, over each tuple, converting
them to lists. Here's one way to do that while keeping it a one-liner:

L1, L2 = map(list, zip(*L))

If L is small, it really doesn't matter what you do, they will all be more
or less as efficient. Write whatever you feel looks best.

But if L is huge, then the difference between a four-liner that iterates
over the list once, and one-liner that iterates over it four times, may be
considerable.

--
Steven

Tim Roberts

unread,
Aug 6, 2011, 8:58:30 PM8/6/11
to

There will always be a loop. It might not be written with a "for"
statement, but there will always be a loop.

L1 = [k[0] for k in L]
L2 = [k[1] for k in L]

I did momentarily consider the following slimy solution:
L1 = dict(L).keys()
L2 = dict(L).values()
but that reorders the tuples. They still correspond, but in a different
order.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Chris Angelico

unread,
Aug 6, 2011, 9:05:14 PM8/6/11
to pytho...@python.org
On Sun, Aug 7, 2011 at 1:58 AM, Tim Roberts <ti...@probo.com> wrote:
> I did momentarily consider the following slimy solution:
>  L1 = dict(L).keys()
>  L2 = dict(L).values()
> but that reorders the tuples.  They still correspond, but in a different
> order.
>

Which can be overcome with collections.OrderedDict. But what's dict(L)
going to do? It's going to loop over L, more than once in fact.

I guess the real question is: Why do you wish to avoid a loop?

ChrisA

Steven D'Aprano

unread,
Aug 6, 2011, 9:35:23 PM8/6/11
to
Chris Angelico wrote:

I think what the Original Poster actually meant was he wanted to avoid
*writing out an explicit loop*. That is, he wants a one-liner, so he
doesn't have to think about the details of iterating over the list.

When we write:

a = sum(a_sequence)

aren't we doing the same thing really?


--
Steven

Paul Rubin

unread,
Aug 7, 2011, 1:29:44 AM8/7/11
to

That is called unzipping and there is a sneaky idiom for it:

L1,L2 = zip(*L)

Your homework assignment is figuring out how that works ;-).

Vito 'ZeD' De Tullio

unread,
Aug 7, 2011, 1:54:08 AM8/7/11
to pytho...@python.org
David Robinow wrote:

L1, L2 = map(list, zip(*L))

--
By ZeD

Gelonida N

unread,
Aug 7, 2011, 1:11:32 PM8/7/11
to pytho...@python.org


Arg typo:

I meant of course zip


>
>


0 new messages