12

If I have

 nums_and_words = [(1, 'one'), (2, 'two'), (3, 'three')]

and would like

nums = [1, 2, 3]
words= ['one', 'two', 'three']

How would I do that in a Pythonic way? It took me a minute to realize why the following doesn't work

nums, words = [(el[0], el[1]) for el in nums_and_words]

I'm curious if someone can provide a similar manner of achieving the result I'm looking for.

Raphi
  • 410
  • 4
  • 17

3 Answers3

16

Use zip, then unpack:

nums_and_words = [(1, 'one'), (2, 'two'), (3, 'three')]
nums, words = zip(*nums_and_words)

Actually, this "unpacks" twice: First, when you pass the list of lists to zip with *, then when you distribute the result to the two variables.

You can think of zip(*list_of_lists) as 'transposing' the argument:

   zip(*[(1, 'one'), (2, 'two'), (3, 'three')])
== zip(  (1, 'one'), (2, 'two'), (3, 'three') )
== [(1, 2, 3), ('one', 'two', 'three')]

Note that this will give you tuples; if you really need lists, you'd have to map the result:

nums, words = map(list, zip(*nums_and_words))
tobias_k
  • 81,265
  • 12
  • 120
  • 179
1

Using List comprehension ..

nums = [nums_and_words[x][0] for x in xrange(len(nums_and_words)) ]
words = [nums_and_words[x][1] for x in xrange(len(nums_and_words)) ]
Testing if this works
print nums ,'&', words 
0

Just unzip and create lists:

nums = list(zip(*nums_and_words)[0])
word = list(zip(*nums_and_words)[1])

See the zip documentation.

Malik Brahimi
  • 16,341
  • 7
  • 39
  • 70
  • I'd hoped to avoid splitting it over two lines. The initial setup I had which I was hoping to get away from was... num = filter(lambda x: x[0], num_and_words) and words = filter(lambda x: x[1], num_and_words) – Raphi Mar 12 '15 at 21:02