5
query = 'select mydata from mytable'
cursor.execute(query)
myoutput = cursor.fetchall() 
print myoutput

(('aa',), ('bb',), ('cc',))

Why is it (cursor.fetchall) returning a tuple of tuples instead of a tuple since my query is asking for only one column of data?

What is the best way of converting it to ['aa', 'bb', 'cc'] ?

I can do something like this :

mylist = []
myoutput = list(myoutput)
for each in myoutput:
   mylist.append(each[0])

I am sure this isn't the best way of doing it. Please enlighten me!

General Grievance
  • 4,555
  • 31
  • 31
  • 45
ThinkCode
  • 7,841
  • 21
  • 73
  • 92

6 Answers6

8

This works as well:

>>> tu = (('aa',), ('bb',), ('cc',))
>>> import itertools
>>> list(itertools.chain(*tu))
['aa', 'bb', 'cc']

Edit Could you please comment on the cost tradeoff? (for loop and itertools)

Itertools is significantly faster:

>>> t = timeit.Timer(stmt="itertools.chain(*(('aa',), ('bb',), ('cc',)))")
>>> print t.timeit()
0.341422080994
>>> t = timeit.Timer(stmt="[a[0] for a in (('aa',), ('bb',), ('cc',))]")
>>> print t.timeit()
0.575773954391

Edit 2 Could you pl explain itertools.chain(*)

That * unpacks the sequence into positional arguments, in this case a nested tuple of tuples.

Example:

>>> def f(*args):
...    print "len args:",len(args)
...    for a in args:
...       print a
... 
>>> tu = (('aa',), ('bb',), ('cc',))
>>> f(tu)
len args: 1
(('aa',), ('bb',), ('cc',))
>>> f(*tu)
len args: 3
('aa',)
('bb',)
('cc',)

Another example:

>>> f('abcde')
len args: 1
abcde
>>> f(*'abcde')
len args: 5
a
b
c
d
e

See the documents on unpacking.

4

You could do

>>> tup = (('aa',), ('bb',), ('cc',))
>>> lst = [a[0] for a in tup]
>>> lst
['aa', 'bb', 'cc']
Chris Taylor
  • 46,912
  • 15
  • 110
  • 154
  • Thank you. I am trying to see if I can do away with the 'for' loop. – ThinkCode Nov 17 '11 at 17:46
  • This code doesn't use a for loop - it uses a list comprehension (although obviously 'under the hood' it is converted into something like a for loop, but one doesn't expect to do something to every element of a list without using some kind of loop, even if its disguised as a list comprehension or some kind of higher order function...) – Chris Taylor Dec 22 '11 at 09:36
2

What you are doing is correct but more concise and may be better performing could be

>>> [item for item, in (('aa',), ('bb',), ('cc',)) ]
['aa', 'bb', 'cc']

or if you hate for keyword, you can use map

>>> map(lambda a:a[0], (('aa',), ('bb',), ('cc',)) )
['aa', 'bb', 'cc']

and here is another way

>>> reduce(lambda a, b:a+b, (('aa',), ('bb',), ('cc',)) )
('aa', 'bb', 'cc')

though IMO list comprehension is most readable

Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
2

Why is cursor.fetchall() returning a tuple of tuples instead of a tuple since my query is asking for only one column of data?

The outer tuple is the complete result; each inner tuple represents one record in that result; because you asked for only one field, each inner tuple has only one element.

What is the best way of converting it to ['aa', 'bb', 'cc'] ?

There are several ways, and which is 'best' depends on what you are doing...

Simple list comprehension:

mylist = [each[0] for each in myoutput]

Simple generator (saves on memory usage):

mygen = (each[0] for each in myoutput)
for result in mygen:
    print result

If you just need to process the items in myoutput, you could also do

for each, in myoutput:
    print each

If you have profiled your code and discovered that this is a bottleneck, then you can go for less readable but faster:

import itertools
mylist = list(itertools.chain(*myoutput))

or, again if you just need to process it:

import itertools
for result in itertools.chain(*myoutput):
    print result
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
1

This works:

>>> tups=(('aa',), ('bb',), ('cc',))
>>> list(*(zip(*tups)))
['aa', 'bb', 'cc']

Explanation:

1) *tups unpacks the nested tuples  ('aa'),('bb'),('cc')
2) zip produces a list of a single tuple with all the elements: [('aa','bb','cc')]
3) * unpacks that  into  'aa', 'bb', 'cc'
4) creates a list from that unpacking.

You could also do:

>>> list(zip(*tups)[0])
['aa', 'bb', 'cc']
dawg
  • 98,345
  • 23
  • 131
  • 206
  • I like it! Could you please explain the list(*(zip(*tups))) part? That way I can remember it easily. – ThinkCode Sep 13 '12 at 19:20
  • *tups and zip's behavior in this case is something new to me. It is clean and elegant too. I am hoping this is performance-efficient too. Thank you! – ThinkCode Sep 13 '12 at 19:39
  • I have Python 2.6.6 on my dev machine and >>> tups=(('aa,','bb,','cc,')) >>> list(*(zip(*tups))) Traceback (most recent call last): File "", line 1, in TypeError: list() takes at most 1 argument (3 given) gives me an error. list(zip(*tups)[0]) works though! – ThinkCode Sep 13 '12 at 19:46
0

Do a list comprehension like this:

mylist = [ x[0] for x in myoutput ]
NEOatNHNG
  • 1
  • 1