11 votes

Python trouver un objet dans une liste

J'ai une liste de personnes :

[
    {'name' : 'John', 'wins' : 10 },
    {'name' : 'Sally', 'wins' : 0 },
    {'name' : 'Fred', 'wins' : 3 },
    {'name' : 'Mary', 'wins' : 6 }
]

J'ajoute des victoires en utilisant une liste de noms ( ['Fred', 'Mary', 'Sally'] ). Je ne sais pas si le nom figure déjà dans la liste des personnes, et je dois insérer un nouvel enregistrement si ce n'est pas le cas. Actuellement, je fais ce qui suit :

name = 'John'
person = None
pidx = None
for p in people_list:
    if p['name'] == name:
        person = p
        pidx = people_list.index(p)
        break
if person is None:
    person = {'name' : name, 'wins' : 0}
person['wins'] += 1
if pidx is None:
    people_list.append(person)
else
    people_list[pidx] = person

Existe-t-il un meilleur moyen de faire cela avec une liste ? Étant donné que j'enregistre ces données dans MongoDB, je ne peux pas utiliser un fichier de type dict car il sera enregistré en tant qu'objet et je veux utiliser les fonctions natives des tableaux pour le tri et le mappage qui ne sont pas disponibles pour les objets.

14voto

DzinX Points 13452

Je suppose ici que vous ne voulez pas utiliser d'autre structure que la liste. Votre code devrait fonctionner, bien que vous réécriviez inutilement le dictionnaire dans la liste après l'avoir mis à jour. Les dictionnaires sont copiés par référence, donc une fois que vous l'avez mis à jour, il reste mis à jour dans la liste. Après un peu de ménage, votre code pourrait ressembler à ceci :

def add_win(people_list, name):
    person = find_person(people_list, name)
    person['wins'] += 1

def find_person(people_list, name):
    for person in people_list:
        if person['name'] == name:
            return person
    person = {'name': name, 'wins': 0}
    people_list.append(person)
    return person

9voto

tangentstorm Points 3818

Oui, utilisez un dict.

wins = {}
for name in winners:
    wins.setdefault(name, 0)
    wins[name] += 1

éditer :

index = {}
for name in wins:
    person = index.setdefault(name, { 'name' : name, 'wins': 0 })
    if person['wins'] == 0:
        person_list.append(person)
    person['wins'] += 1

7voto

StephenPaulger Points 2113

Si vous ne voulez pas d'une dictée permanente, utilisez-en une temporairement.

people = [
    {'name' : 'John', 'wins' : 10 },
    {'name' : 'Sally', 'wins' : 0 },
    {'name' : 'Fred', 'wins' : 3 },
    {'name' : 'Mary', 'wins' : 6 }
]

wins = ['Fred', 'Mary', 'Sally']

people_dict = dict((p["name"], p) for p in people)

for winner in wins:
    people_dict[winner].setdefault("wins", 0)
    people_dict[winner]["wins"] += 1

people = people_dict.values()

4voto

Nick Bastin Points 12627

Votre modèle d'accès impose l'utilisation d'une structure de données différente (ou au moins d'une autre structure de données auxiliaire). Scanner la liste comme vous le faites est en fait la bonne chose à faire si vous utilisez une liste, mais vous ne devriez pas utiliser une liste (si vous voulez qu'elle soit efficace, de toute façon).

Si l'ordre de la liste n'a pas d'importance, vous devriez utiliser un Dictionnaire (python dict ). Si c'est le cas, vous devez utiliser un OrderedDict de la collections module.

Vous pourriez aussi utiliser deux structures de données distinctes - la liste que vous avez déjà, et en plus une set contenant uniquement les noms de la liste, ce qui vous permet d'accéder rapidement au test d'inclusion ou non. Cependant, le set ne vous aide pas à accéder rapidement aux données réelles du nom (vous devez toujours faire une recherche linéaire dans la liste pour cela), donc ce ne serait un motif utile que si vous testez simplement l'inclusion, mais sinon vous parcourez toujours la liste au fur et à mesure qu'elle est insérée.

Modifier Il semble que ce que vous voulez en fait, c'est une liste et un dict, où le dictionnaire est un mappage entre les éléments suivants name et l'indice dans la liste. Alternativement, vous pouvez toujours utiliser un dict ou OrderedDict mais les insérer dans Mongo sous forme de tableau en utilisant dict.iteritems() pour créer un tableau (ou ce qui ressemble à un tableau pour Mongo) lors de l'insertion. Vous pouvez utiliser divers mutateurs de zip aux choses dans itertools pour construire dynamiquement les objets dont vous avez besoin dans votre tableau résultant.

0voto

Simon Buchan Points 6245

Ce cas spécifique est mis en œuvre par le collections.Counter type. Avec les générateurs de tableaux, c'est une expression :

[{'name':name, 'wins':wins}
 for name, wins in Counter(names).items()]

Si vous voulez une commande spécifique, sorted() est la méthode la plus simple (elle utilise également un générateur simple). () plutôt qu'un générateur de tableau [] puisque c'est temporaire) :

sorted(({'name':name, 'wins':wins} for name, wins in Counter(names).items()),
       key=lambda item: item['name'])

Donde item['name'] pourrait être item['wins'] ou toute autre expression comparable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X