2010-03-24 12 views
2

J'ai une liste de dictionnaires:catalogue une liste de dictionnaires

people = [{"name": "Roger", "city": "NY", "age": 20, "sex": "M"}, 
      {"name": "Dan", "city": "Boston", "age": 20, "sex": "M"}, 
      {"name": "Roger", "city": "Boston", "age": 21, "sex": "M"}, 
      {"name": "Dana", "city": "Dallas", "age": 30, "sex": "F"}] 

Je veux les cataloguer, par exemple, je choisis ces clés:

field = ("sex", "age") 

je besoin d'une fonction catalogue(field, people) qui me donne :

{ "M": 
     { 20: [{"name": "Roger", "city": "NY", "age": 20, "sex": "M"}, 
      {"name": "Dan", "city": "Boston", "age": 20, "sex": "M"}], 
     21: [{"name": "Roger", "city": "Boston", "age": 21, "sex": "M"}] 
     }, 
{ "F": 
     { 30: [{"name": "Dana", "city": "Dallas", "age": 30, "sex": "F"}] } 
} 

lorsque c'est len(field)==1 c'est simple. Je veux faire quelque chose comme ceci:

c = catalogue(field, people) 
for (sex, sex_value) in c.iteritems(): 
    for (age, age_value) in sex_value.iteritems(): 
     print sex, age, age_value["name"] 
+0

une autre question simple: quel est le meilleur nom pour cette fonction? J'ai utilisé 'catalog', est-ce correct? –

+0

le catalogue semble correct –

Répondre

8

récursive:

import itertools, operator 

def catalog(fields,people): 
    cur_field = operator.itemgetter(fields[0]) 
    groups = itertools.groupby(sorted(people, key=cur_field),cur_field) 
    if len(fields)==1: 
     return dict((k,list(v)) for k,v in groups) 
    else: 
     return dict((k,catalog(fields[1:],v)) for k,v in groups) 

test:

import pprint 
pprint.pprint(catalog(('sex','age'), people)) 
{'F': {30: [{'age': 30, 'city': 'Dallas', 'name': 'Dana', 'sex': 'F'}]}, 
'M': {20: [{'age': 20, 'city': 'NY', 'name': 'Roger', 'sex': 'M'}, 
      {'age': 20, 'city': 'Boston', 'name': 'Dan', 'sex': 'M'}], 
     21: [{'age': 21, 'city': 'Boston', 'name': 'Roger', 'sex': 'M'}]}} 
+2

N'utilisez jamais jamais 'import *'. –

+2

:) bien, corrigé – Jimmy

+1

Une remarque utile est que vous pouvez créer une fonction de recherche en utilisant la fonction d'usine operator.itemgetter. c'est-à-dire remplacer la première ligne par 'cur_field = operator.itemgetter (champs [0])' Cela semble un peu plus agréable, et est également légèrement plus rapide. – Brian

0
import pprint 
people = [{"name": "Roger", "city": "NY", "age": 20, "sex": "M"}, 
      {"name": "Dan", "city": "Boston", "age": 20, "sex": "M"}, 
      {"name": "Roger", "city": "Boston", "age": 21, "sex": "M"}, 
      {"name": "Dana", "city": "Dallas", "age": 30, "sex": "F"}] 
fields = ("sex", "age") 
result = {} 
for person in people: 
    tempdict = result 
    for field in fields[:-1]: 
     if person[field] in tempdict: 
      tempdict = tempdict[person[field]] 
     else: 
      t = tempdict 
      tempdict = {} 
      t[person[field]] = tempdict 
    key = person[fields[-1]] 
    if key in tempdict: 
     tempdict[key].append(person) 
    else: 
     tempdict[key] = [person] 

pprint.pprint(result) 

semble faire le travail

0

pas optimale (pourrait être améliorée en utilisant defaultdict, fo Par exemple, mais j'avais Python2.4 installé sur ma machine), mais fait le travail:

def catalogue(dicts, criteria): 
    if not criteria: 
     return dicts 

    criterion, rest = criteria[0], criteria[1:] 

    cat = {} 
    for d in dicts: 
     reducedDict = dict(d) 
     del reducedDict[criterion] 

     if d[criterion] in cat: 
      cat[d[criterion]].append(reducedDict) 
     else: 
      cat[d[criterion]] = [reducedDict] 

    retDict = {} 
    for key, val in cat.items(): 
     retDict[key] = catalogue(val, rest) 

    return retDict 

print catalogue(people, ("sex", "age"))