views:

204

answers:

3

for example if i had the result

[{'Germany': {"Luge - Men's Singles": 'Gold'}}, 
{'Germany': {"Luge - Men's Singles": 'Silver'}},
{'Italy': {"Luge - Men's Singles": 'Bronze'}}]
[{'Germany': {"Luge - Women's Singles": 'Gold'}},
{'Austria': {"Luge - Women's Singles": 'Silver'}},
{'Germany': {"Luge - Women's Singles": 'Bronze'}}]
[{'Austria': {'Luge - Doubles': 'Gold'}}, 
{'Latvia': {'Luge - Doubles': 'Silver'}},
{'Germany': {'Luge - Doubles': 'Bronze'}}]

how would I sort this so that all of the events germany and so on had won could be under one single title. i.e germany would be germany:Luge - Men's Singles: Gold, Silver, Luge - Women's Singles: Gold, Bronze, Luge - Doubles: Bronze.

thanks for any help

EDIT: this is a straight copy and paste from the python shell now to help confusion:

[{'Germany': {"Luge - Men's Singles": 'Gold'}}, {'Germany': {"Luge - Men's Singles": 'Silver'}}, {'Italy': {"Luge - Men's Singles": 'Bronze'}}] [{'Germany': {"Luge - Women's Singles": 'Gold'}}, {'Austria': {"Luge - Women's Singles": 'Silver'}}, {'Germany': {"Luge - Women's Singles": 'Bronze'}}] [{'Austria': {'Luge - Doubles': 'Gold'}}, {'Latvia': {'Luge - Doubles': 'Silver'}}, {'Germany': {'Luge - Doubles': 'Bronze'}}]

sorry about that im new to this site. It loops round 3 time one for each different event and i was wondering if i could get the desired from merging it after the final loop?

+4  A: 
import collections

merged_result = collections.defaultdict(list)

for L in listoflistsofdicts:
  for d in L:
    for k in d:
      merged_result[k].append(d[k])

or if you just have a list of dicts instead of a list of lists of dicts (hard to say from your Q!-), then just the

  for d in listofdicts:
    for k in d:
      merged_result[k].append(d[k])

part of the loop.

If you want strings rather than lists as the values of merged_result then after the above code add

for k in merged_result:
    merged_result[k] = ', '.join(merged_result[k])

or, equivalently (but building a new plain dict instead of the defaultdict):

merged_result = dict((k, ', '.join(v)) for k, v in merged_result.iteritems())

(this assumes Python 2.* -- in Python 3, use .items instead of .iteritems).

Edit: looking at the sample code it looks like it's invalid syntax for a list of list of dicts (missing commas) so I showed how to deal with that, too.

Alex Martelli
Hah, we have an interpret-off. Which one of us interpreted the question correctly! :)
Thomas Wouters
On second viewing, it's obvious you were interpreting it correctly ;P
Thomas Wouters
@Thomas, still not obvious to me, but, we'll see (one hopes;-).
Alex Martelli
+1  A: 

(Sorry, I really meant this as a comment on Alex Martelli's answer, since mine is based on his; but when I originally posted I didn't have enough reputation to comment)

Alex's answer doesn't actually generate the intended result. I don't mean the finer points of having a list of lists of dicts, or the lack of commas between the lists (more on that later). But the original question wanted, as a result, a compilation of all medals by country, by competition. Alex's solution will answer:

> 'Germany': [{"Luge - Men's Singles": 'Gold'},
             {"Luge - Men's Singles": 'Silver'},
             {"Luge - Women's Singles": 'Gold'},
             {"Luge - Women's Singles": 'Bronze'},
             {'Luge - Doubles': 'Bronze'}]

But I believe the original question actually asked for:

> 'Germany': [{"Luge - Men's Singles": ['Gold', 'Silver']},
             {"Luge - Women's Singles": ['Gold', 'Bronze'},
             {'Luge - Doubles': 'Bronze'}]

The data in the question is a bit confusing, I see two possibilities:

1) The data shown is actually three different examples, and the task is to merge dict entries within each list, separately. That is, given

[{'Germany': {"Luge - Men's Singles": 'Gold'}}, 
{'Germany': {"Luge - Men's Singles": 'Silver'}},
{'Italy': {"Luge - Men's Singles": 'Bronze'}}]

you want

['Germany': {"Luge - Men's Singles": ['Gold', 'Silver'],
             "Luge - Women's Singles": ['Gold', 'Bronze']},
 'Italy': {"Luge - Men's Singles": ['Bronze']}]

, given

[{'Germany': {"Luge - Women's Singles": 'Gold'}},
{'Austria': {"Luge - Women's Singles": 'Silver'}},
{'Germany': {"Luge - Women's Singles": 'Bronze'}}]

you want

['Germany': {"Luge - Women's Singles": ['Gold', 'Bronze']},
 'Austria': {"Luge - Women's Singles": ['Silver']}]

and so on. I gather this is the most likely interpretation of the question.

The following code does that:

from collections import defaultdict

merged = defaultdict(lambda: defaultdict(list))
for d in list_of_dicts:
    for k in d:
        for competition, medal in d[k].iteritems():
            merged[k][competition].append(medal)

Running this for the first of the lists shown above, you get

defaultdict(<function <lambda> at 0x1907db0>,
 {'Italy': defaultdict(<type 'list'>, {"Luge - Men's Singles": ['Bronze']}),
  'Germany': defaultdict(<type 'list'>, {"Luge - Men's Singles": ['Gold', 'Silver']})})

2) The second possibility is that the data in the question is one single list, containing 3 lists, each of these containing dicts. I think this is not what the original question means, but, since I'd already written the code for that, here it is :)

from collections import defaultdict

merged = defaultdict(lambda: defaultdict(list))
for L in listoflistsofdicts:
  for d in L:
    for k in d:
      for competition, medal in d[k].iteritems():
          merged[k][competition].append(medal)

Running the code above for the lists shown on the question (with the necessary commas added, you get:

 defaultdict(<function <lambda> at 0x1904b70>,
    {'Italy': defaultdict(<type 'list'>, {"Luge - Men's Singles": ['Bronze']}),
     'Austria': defaultdict(<type 'list'>, {'Luge - Doubles': ['Gold'],
                                            "Luge - Women's Singles": ['Silver']}),
     'Latvia': defaultdict(<type 'list'>, {'Luge - Doubles': ['Silver']}),
     'Germany': defaultdict(<type 'list'>, {'Luge - Doubles': ['Bronze'],
                                            "Luge - Men's Singles": ['Gold', 'Silver'],
                                            "Luge - Women's Singles": ['Gold', 'Bronze']})
    })

Please note that both of these codes don't sort medal types (i.e., you might end up with ['Gold', 'Silver'] or ['Silver', 'Gold']).

Of course, if you get separated lists as used in solution 1), but need a merge of all of them, simply bring them all together in a list, and use solution 2).

rbp
thanks for the update it worked out for me in the end. think this is the answer im going to use. ill make it correct when i figure out how.
Kevin
Cool, good to know :)
rbp
A: 

thanks for thw help there guys there just one problem with it though, i think its probably to do with the way i wrote the question but still in both solutions you use the line "for competition, medal in d[k].items(): (or merged_result[k].append(d[k]) in the first case) when i type this in o my code in python it keeps giving me the error of "TypeError : string inices must be integers, not str" again maybe this is just the way my question in worded but i cant figure out a way round this, can you help me?

Kevin
I think your original data is different than what you posted here. Where we assumed there would be a dictionary, is a string. Could you perhaps edit your question to make it clear what your original data is? The way you posted it, it's not even valid (there should be commas between the outermost lists). Perhaps copy/paste right out of the Python prompt.Now that I look at it once more, something occurs to me: does the snippet you posted represent *one* data structure, consisting of 3 lists, each of which has dictionaries? Or is it *three* examples, each one a list of dictionaries?
rbp