1

I have following code (which produces a syntax error, btw). Can someone help me fixing it so I can get a version that produces the expected result?

al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
a, b, c = [i.a, i.b, i.c for i in al]

Expected result:

a = [1, 4, 7, 10]
b = [2, 5, 8, 11]
c = [3, 6, 9, 12]
1
  • If you really must show the keys in code. In situations like that I usually build the dictionnairy dynamically and do a import pprint; pprint mydict , That way I can create a pep8 compliant dict Commented Sep 11, 2013 at 5:52

8 Answers 8

4

If you know keys in advance:

>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> a, b, c = [[d[key] for d in al] for key in 'abc'] # ('a', 'b', 'c')
>>> a
[1, 4, 7, 10]
>>> b
[2, 5, 8, 11]
>>> c
[3, 6, 9, 12]

If you don't know keys in advance:

>>> d = {key: [d[key] for d in al] for key in al[0]}
>>> d
{'a': [1, 4, 7, 10], 'c': [3, 6, 9, 12], 'b': [2, 5, 8, 11]}
>>> a, b, c = map(d.get, 'abc') # OR map(d.get, ('a', 'b', 'c'))
>>> a
[1, 4, 7, 10]
>>> b
[2, 5, 8, 11]
>>> c
[3, 6, 9, 12]
Sign up to request clarification or add additional context in comments.

4 Comments

How about [dict_.values() for dict_ in al]
@PauloScardine, It does not produce what OP want.
Indeed, I forgot order is not guaranteed in python dicts.
Great. I don't know the keys in advance, sort of. The dictionary list will be returned by a web service which may or may not contain some fields. The second approach seems the perfect answer here.
1

If your keys are unknown, you can simply transpose the data and create another transpose dictionary, which you can simply access by the keys instead of creating standalone variables

>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> keys = al[0].keys()
>>> #Given your list of dictionary
>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> #determine the keys
>>> keys = al[0].keys()
>>> #and using itemgetter
>>> from operator import itemgetter
>>> #create a transpose dictionary
>>> al_transpose = dict(zip(keys,zip(*map(itemgetter(*keys),al))))
>>> al_transpose['a']
(1, 4, 7, 10)
>>> al_transpose['b']
(2, 5, 8, 11)
>>> al_transpose['c']
(3, 6, 9, 12)

Note Not Recommended

If you actually want to create standalone variables, you can do so by adding the dictionary to the locals

locals().update(al_transpose)
>>> a
(1, 4, 7, 10)
>>> b
(2, 5, 8, 11)
>>> c
(3, 6, 9, 12)

Comments

0

If you're interested in a one-liner, and if you guarantee the order and presence of the keys in the dicts of al, then:

>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> dict(zip(al[0].keys(),zip(*[i.values() for i in al])))
{'a': (1, 4, 7, 10), 'c': (3, 6, 9, 12), 'b': (2, 5, 8, 11)}

1 Comment

This is a bit silly since you can't guarantee the order of the keys in the dict
0

Try this

a,b,c = [map(lambda x:x[ele], al) for ele in 'abc']

Comments

0

You could do something like this:

al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]

result={}
for dic in al:
    for key,val in dic.items():
        result.setdefault(key,[]).append(val)

print result     
# {'a': [1, 4, 7, 10], 'c': [3, 6, 9, 12], 'b': [2, 5, 8, 11]}
a,b,c=result['a'],result['b'],result['c']   

print a,b,c
# [1, 4, 7, 10] [2, 5, 8, 11] [3, 6, 9, 12]

If you want to bind the names in the dictionary to names in the current name space, you can do this:

al = [{'a': 1, 'b': 2, 'c': 3, 'd':4}, 
      {'a': 4, 'b': 5, 'c': 6}, 
      {'a': 7, 'b': 8, 'c': 9}]

result={}
for dic in al:
    for k in dic:
        result.setdefault(k,[]).append(dic[k])

print result     
# {'a': [1, 4, 7, 10], 'c': [3, 6, 9, 12], 'b': [2, 5, 8, 11], 'd': [4]}

for k in result:
    code=compile('{}=result["{}"]'.format(k,k), '<string>', 'exec')
    exec code

print a,b,c,d  
# [1, 4, 7, 10] [2, 5, 8, 11] [3, 6, 9, 12] [4]

Comments

0
>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> from operator import itemgetter
>>> a, b, c = zip(*map(itemgetter(*'abc'),(al)))
>>> a
(1, 4, 7, 10)
>>> b
(2, 5, 8, 11)
>>> c
(3, 6, 9, 12)

Comments

0
>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> a, b, c = zip(*(sorted(x.values(), key=x.get) for x in al))
>>> a
(1, 4, 7, 10)
>>> b
(3, 6, 9, 12)
>>> c
(2, 5, 8, 11)

Comments

0

This is how you need to modify your method

>>> al = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}, {'a': 7, 'b': 8, 'c': 9}, {'a': 10, 'b': 11, 'c': 12}]
>>> a, b, c = zip(*((i['a'], i['b'], i['c']) for i in al))

Firstly, you need to use i['a'] instead of i.a etc. since a is a key, not an attribute

So that would give you

>>> [(i['a'], i['b'], i['c']) for i in al]
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)]

Ah, the rows and columns are the wrong way around. They standard trick to swap the rows and columns is zip(*A)

>>> zip(*[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12)])
[(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]

Combining those two ideas gives the expression at the top of this answer

A more direct approach is a nested list comprehension

>>> a, b, c = [[x[k] for x in al] for k in 'abc']

If the keys are not single characters, you need to write them out as a tuple longhand

>>> a, b, c = [[x[k] for x in al] for k in ('a', 'b', 'c')]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.