Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Comment trouver dans un dictionnaire l'entrée qui a le plus d'occurence avec une liste donnée ?

+4 votes

J'ai un dictionnaire rempli de recette suivant ce format :

{'ingredient_1': 'XXX', 'ingredient_2': 'XXX', 'ingredient_3': 'XXX',  'ingredient_4': 'XXX', 'name': 'XXX', 'recipe':'XXX'}

Je reçois de l'utilisateur une liste d'ingrédients :

['XXX', 'XXX', 'XXX', 'XXX']

J'essaye de déterminer la recette qui a la plus d'ingrédients en commun avec la liste donnée par l'utilisateur.

demandé 6-Mar-2015 par Elhebert
edité 6-Mar-2015 par foxmask

1 Réponse

+7 votes
 
Meilleure réponse

Tu peux utiliser cet operateur pour trouver l'intersection de deux listes (voir ici):

set(['pommes', 'abricots', 'poires']) & set(['porc', 'abricots', 'chocolat en poudre'])
>>> set(['abricots'])

Du coup, si on applique à ton problème, il te suffit de mesurer la taille du set retourné par cette intersection pour savoir quelle recette à le plus d'éléments en commun.

Je te suggère également (mais je ne connais pas ton projet) d'utiliser des objets plutôt que des dictionnaires, et de ne pas créer de clés 'ingredient1', 'ingredient2', 'ingredient_3', mais plutôt une clé 'ingredients', qui stockera une liste d'ingredient.

Exemple:

# -*- coding: utf-8 -*-

class Recipe(object):

    def __init__(self, ingredients, name):
        self.ingredients = ingredients
        self.name = name

    def get_common_ingredients_score(self, ingredients):
        """Une fonction qui prends une liste d'ingrédients en entrée
        et retourne un entier correspondant au nombre d'éléments en commun
        avec les ingrédients de l'instance"""

        return len(set(self.ingredients) & set(ingredients))


def get_closest_recipes(recipes, ingredients):
    """Retourne une liste de de tuples à partir des ingrédients fournis par l'utilisateur
    Chaque tuple contient une recette et son score de pertinence par rapport aux ingrédients fournis"""

    closest_recipes = [(recipe, recipe.get_common_ingredients_score(ingredients)) for recipe in recipes]

    # on ordonne la liste par score inversé
    closest_recipes = sorted(closest_recipes, key=lambda x: x[1], reverse=True)
    return closest_recipes


recipes = [
    Recipe(ingredients=['pommes', 'pate feuilletée', "de l'amour"], name='Tarte aux pommes'),
    Recipe(ingredients=['pommes', 'chausson', 'du temps'], name='Chausson aux pommes'),
    Recipe(ingredients=['pate feuilletée', 'une fille appelée Lorraine', "de l'amour"], name='Quiche lorraine'),
    Recipe(ingredients=['choux', 'du temps', "de l'amour"], name='Choucroute garnie'),
]


assert get_closest_recipes(recipes, ["de l'amour", "du temps"])[0][0].name == 'Choucroute garnie'
assert get_closest_recipes(recipes, ['pommes', 'pate feuilletée'])[0][0].name == 'Tarte aux pommes'

Si tu ne peux pas changer ta structure de données, ça marche quand même, il faut juste modifier légèrement le script:

def get_common_ingredients_score(recipe, ingredients):
    return len(set([recipe['ingredient_1'], recipe['ingredient_2'], recipe['ingredient_3'], recipe['ingredient_4']]) & set(ingredients))

def get_closest_recipes(recipes, ingredients):
    """Retourne une liste de de tuples à partir des ingrédients fournis par l'utilisateur
    Chaque tuple contient une recette et son score de pertinence par rapport aux ingrédients fournis"""

    # d'abord, on construit une liste d'ingrédients associée au nom de chaque recette
    closest_recipes = [(recipe, get_common_ingredients_score(recipe, ingredients)) for recipe in recipes]

    # on ordonne la liste par score inversé
    closest_recipes = sorted(closest_recipes, key=lambda x: x[1], reverse=True)
    return closest_recipes
répondu 7-Mar-2015 par eliotberriot (678 points)
edité 7-Mar-2015 par eliotberriot
...